diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..eef634fae2a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,9 @@ +{ + "extensions": [ + "github.vscode-codeql", + "slevesque.vscode-zipexplorer" + ], + "settings": { + "codeQL.experimentalBqrsParsing": true + } +} diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000000..638f30dd4ce --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,9 @@ +name: "CodeQL config" + +queries: + - uses: security-and-quality + +paths-ignore: + - '/cpp/' + - '/java/' + - '/python/' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000000..f1844da86cf --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,52 @@ +name: "Code scanning - action" + +on: + push: + pull_request: + schedule: + - cron: '0 9 * * 1' + +jobs: + CodeQL-Build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + with: + languages: csharp + config-file: ./.github/codeql/codeql-config.yml + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b6cffedcaf..fa88395e5d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ 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! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). -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). +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 [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com). ## Submitting a new experimental query @@ -32,7 +32,7 @@ If you have an idea for a query that you would like to share with other CodeQL u For details, see the [guide on query metadata](docs/query-metadata-style-guide.md). - 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. + Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com. 3. **Formatting** @@ -53,14 +53,6 @@ After the experimental query is merged, we welcome pull requests to improve it. ## 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 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 -on the basis of our legitimate interest in creating the CodeQL product. - -Please do get in touch (privacy@github.com) if you have any questions about -this or our data protection policies. +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 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 CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. +Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies. diff --git a/README.md b/README.md index 19d38c3b40a..08e572a0246 100644 --- a/README.md +++ b/README.md @@ -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 CodeQL products that [GitHub](https://github.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. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go). ## How do I learn CodeQL and run queries? diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md new file mode 100644 index 00000000000..47997f07052 --- /dev/null +++ b/change-notes/1.25/analysis-cpp.md @@ -0,0 +1,46 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.25 affect C/C++ analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| +| Uncontrolled format string (`cpp/tainted-format-string`) | | This query is now displayed by default on LGTM. | +| Uncontrolled format string (through global variable) (`cpp/tainted-format-string-through-global`) | | This query is now displayed by default on LGTM. | + +## Changes to libraries + +* The library `VCS.qll` and all queries that imported it have been removed. +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through functions now takes nested field reads/writes into account. + For example, the library is able to track flow from `taint()` to `sink()` via the method + `getf2f1()` in + ```c + struct C { + int f1; + }; + + struct C2 + { + C f2; + + int getf2f1() { + return f2.f1; // Nested field read + } + + void m() { + f2.f1 = taint(); + sink(getf2f1()); // NEW: taint() reaches here + } + }; + ``` +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library. +* The length of a tainted string (such as the return value of a call to `strlen` or `strftime` with tainted parameters) is no longer itself considered tainted by the `models` library. This leads to fewer false positive results in queries that use any of our taint libraries. diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md new file mode 100644 index 00000000000..de4761c9248 --- /dev/null +++ b/change-notes/1.25/analysis-csharp.md @@ -0,0 +1,54 @@ +# Improvements to C# analysis + +The following changes in version 1.25 affect C# analysis in all applications. + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| + + +## Removal of old queries + +## Changes to code extraction + +* Index initializers, of the form `{ [1] = "one" }`, are extracted correctly. Previously, the kind of the + expression was incorrect, and the index was not extracted. + +## Changes to libraries + +* The class `UnboundGeneric` has been refined to only be those declarations that actually + have type parameters. This means that non-generic nested types inside constructed types, + such as `A.B`, no longer are considered unbound generics. (Such nested types do, + however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through methods now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `Sink()` via the method + `GetF2F1()` in + ```csharp + class C1 + { + string F1; + } + + class C2 + { + C1 F2; + + string GetF2F1() => F2.F1; // Nested field read + + void M() + { + F2 = new C1() { F1 = "taint" }; + Sink(GetF2F1()); // NEW: "taint" reaches here + } + } + ``` + +## Changes to autobuilder diff --git a/change-notes/1.25/analysis-java.md b/change-notes/1.25/analysis-java.md new file mode 100644 index 00000000000..7cdd9e491a2 --- /dev/null +++ b/change-notes/1.25/analysis-java.md @@ -0,0 +1,41 @@ +# Improvements to Java analysis + +The following changes in version 1.25 affect Java analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| + + +## Changes to libraries + +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through methods now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `sink()` via the method + `getF2F1()` in + ```java + class C1 { + String f1; + C1(String f1) { this.f1 = f1; } + } + + class C2 { + C1 f2; + String getF2F1() { + return this.f2.f1; // Nested field read + } + void m() { + this.f2 = new C1("taint"); + sink(this.getF2F1()); // NEW: "taint" reaches here + } + } + ``` diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 7770b250acc..be811bd8e5a 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,24 +3,106 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) + - [bluebird](http://bluebirdjs.com/) + - [express](https://www.npmjs.com/package/express) + - [fancy-log](https://www.npmjs.com/package/fancy-log) + - [fastify](https://www.npmjs.com/package/fastify) + - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) + - [marsdb](https://www.npmjs.com/package/marsdb) + - [micro](https://www.npmjs.com/package/micro/) + - [minimongo](https://www.npmjs.com/package/minimongo/) + - [mssql](https://www.npmjs.com/package/mssql) + - [mysql](https://www.npmjs.com/package/mysql) + - [npmlog](https://www.npmjs.com/package/npmlog) + - [pg](https://www.npmjs.com/package/pg) + - [sequelize](https://www.npmjs.com/package/sequelize) + - [spanner](https://www.npmjs.com/package/spanner) + - [sqlite](https://www.npmjs.com/package/sqlite) + - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) + - [ssh2](https://www.npmjs.com/package/ssh2) + - [vue](https://www.npmjs.com/package/vue) + - [yargs](https://www.npmjs.com/package/yargs) + - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) + +* TypeScript 3.9 is now supported. + +* TypeScript code embedded in HTML and Vue files is now extracted and analyzed. + +* The analysis of sanitizers has improved, leading to more accurate + results from the security queries. ## New queries | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | +| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | +| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | +| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. | +| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. | +| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | +| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | +| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. | +| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. | ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| +| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | +| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | +| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. | +| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | Fewer results | This query no longer flags paths that have been checked to be part of a collection. | +| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. | +| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | + +The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): + + - `js/angular/dead-event-listener` + - `js/angular/unused-dependency` + - `js/bitwise-sign-check` + - `js/comparison-of-identical-expressions` + - `js/conflicting-html-attribute` + - `js/ignored-setter-parameter` + - `js/jsdoc/malformed-param-tag` + - `js/jsdoc/missing-parameter` + - `js/jsdoc/unknown-parameter` + - `js/json-in-javascript-file` + - `js/misspelled-identifier` + - `js/nested-loops-with-same-variable` + - `js/node/cyclic-import` + - `js/node/unused-npm-dependency` + - `js/omitted-array-element` + - `js/return-outside-function` + - `js/single-run-loop` + - `js/too-many-parameters` + - `js/unused-property` + - `js/useless-assignment-to-global` ## Changes to libraries +* A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph. * Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module. +* The data-flow node representing a parameter or destructuring pattern is now always the `ValueNode` corresponding to that AST node. This has a few consequences: + - `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph. + - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. + - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. +* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function". +* The predicates `Type.getProperty()` and variants of `Type.getMethod()` have been deprecated due to lack of use-cases. Looking up a named property of a static type is no longer supported, favoring faster extraction times instead. diff --git a/change-notes/1.25/analysis-python.md b/change-notes/1.25/analysis-python.md new file mode 100644 index 00000000000..5d0fc69ec80 --- /dev/null +++ b/change-notes/1.25/analysis-python.md @@ -0,0 +1,22 @@ +# Improvements to Python analysis + +The following changes in version 1.25 affect Python analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + + +## Changes to libraries + +* Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`). diff --git a/config/identical-files.json b/config/identical-files.json index a5af067ab5d..71c507e3993 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -1,5 +1,5 @@ { - "DataFlow Java/C++/C#": [ + "DataFlow Java/C++/C#/Python": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll", @@ -18,15 +18,18 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll" ], - "DataFlow Java/C++/C# Common": [ + "DataFlow Java/C++/C#/Python Common": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll" ], - "TaintTracking::Configuration Java/C++/C#": [ + "TaintTracking::Configuration Java/C++/C#/Python": [ "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", @@ -37,13 +40,15 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll" + "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", + "python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" ], - "DataFlow Java/C++/C# Consistency checks": [ + "DataFlow Java/C++/C#/Python Consistency checks": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll" ], "C++ SubBasicBlocks": [ "cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll", @@ -53,114 +58,122 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Operand.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll" ], "IR IRType": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll" + "csharp/ql/src/experimental/ir/implementation/IRType.qll" ], "IR IRConfiguration": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll" ], "IR UseSoundEscapeAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll" + ], + "IR IRFunctionBase": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll", + "csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll" ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll" + "csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll" + ], + "IR TInstruction":[ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll", + "csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll" ], "IR TIRVariable":[ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll" ], "IR IR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll" ], - "IR IRSanity": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll" + "IR IRConsistency": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll", + "csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll" ], "IR IntegerConstant": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll" + "csharp/ql/src/experimental/ir/internal/IntegerConstant.qll" ], "IR IntegerInteval": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll" + "csharp/ql/src/experimental/ir/internal/IntegerInterval.qll" ], "IR IntegerPartial": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll" + "csharp/ql/src/experimental/ir/internal/IntegerPartial.qll" ], "IR Overlap": [ "cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll" + "csharp/ql/src/experimental/ir/internal/Overlap.qll" ], "IR EdgeKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll" + "csharp/ql/src/experimental/ir/implementation/EdgeKind.qll" ], "IR MemoryAccessKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll" + "csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll" ], "IR TempVariableTag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll" + "csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll" ], "IR Opcode": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll" + "csharp/ql/src/experimental/ir/implementation/Opcode.qll" ], - "IR SSASanity": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll" + "IR SSAConsistency": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" ], "C++ IR InstructionImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", @@ -177,6 +190,11 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll" ], + "C++ IR IRFunctionImports": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll" + ], "C++ IR IRVariableImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll", @@ -199,7 +217,7 @@ "SSA AliasAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" ], "C++ SSA AliasAnalysisImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll", @@ -212,42 +230,42 @@ ], "IR SSA SimpleSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" ], "IR AliasConfiguration (unaliased_ssa)": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" ], "IR SSA SSAConstruction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" ], "IR SSA PrintSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" ], "IR ValueNumberInternal": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" ], "C++ IR ValueNumber": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" ], "C++ IR PrintValueNumbering": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" ], "C++ IR ConstantAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll", @@ -276,32 +294,36 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], "C# IR InstructionImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" ], "C# IR IRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll" ], "C# IR IRBlockImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" + ], + "C# IR IRFunctionImports": [ + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll" ], "C# IR IRVariableImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" ], "C# IR OperandImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll" ], "C# IR PrintIRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" ], "C# IR ValueNumberingImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" ], "XML": [ "cpp/ql/src/semmle/code/cpp/XML.qll", diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py new file mode 100644 index 00000000000..e379e6a3ea9 --- /dev/null +++ b/config/opcode-qldoc.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import os +import re +path = os.path + +needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a". +start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment +end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment +blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' +instruction_class_re = re.compile(r'^class (?P[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class +opcode_base_class_re = re.compile(r'^abstract class (?P[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class +opcode_class_re = re.compile(r'^ class (?P[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class + +script_dir = path.realpath(path.dirname(__file__)) +instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) +opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll')) + +# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class +# whose name ends with `Instruction`. +instruction_comments = {} +in_qldoc = False +saw_blank_line_in_qldoc = False +qldoc_lines = [] +with open(instruction_path, 'r', encoding='utf-8') as instr: + for line in instr: + if in_qldoc: + if end_qldoc_re.search(line): + qldoc_lines.append(line) + in_qldoc = False + elif blank_qldoc_line_re.search(line): + # We're going to skip any lines after the first blank line, to avoid duplicating all + # of the verbose description. + saw_blank_line_in_qldoc = True + elif not saw_blank_line_in_qldoc: + qldoc_lines.append(line) + else: + if start_qldoc_re.search(line): + # Starting a new QLDoc comment. + saw_blank_line_in_qldoc = False + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + instruction_match = instruction_class_re.search(line) + if instruction_match: + # Found the declaration of an `Instruction` class. Record the QLDoc comments. + instruction_comments[instruction_match.group('name')] = qldoc_lines + qldoc_lines = [] + +# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a +# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment. +in_qldoc = False +qldoc_lines = [] +output_lines = [] +with open(opcode_path, 'r', encoding='utf-8') as opcode: + for line in opcode: + if in_qldoc: + qldoc_lines.append(line) + if end_qldoc_re.search(line): + in_qldoc = False + else: + if start_qldoc_re.search(line): + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + name_without_suffix = None + name = None + indent = '' + opcode_base_match = opcode_base_class_re.search(line) + if opcode_base_match: + name_without_suffix = opcode_base_match.group('name') + name = name_without_suffix + 'Opcode' + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + name_without_suffix = opcode_match.group('name') + name = name_without_suffix + # Indent by two additional spaces, since opcodes are declared in the + # `Opcode` module. + indent = ' ' + + if name_without_suffix: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + if instruction_comments.get(name_without_suffix): + article = 'an' if needs_an_re.search(name_without_suffix) else 'a' + qldoc_lines = [ + indent + '/**\n', + indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n', + indent + ' *\n', + indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n', + indent + ' */\n' + ] + output_lines.extend(qldoc_lines) + qldoc_lines = [] + output_lines.append(line) + +# Write out the updated `Opcode.qll` +with open(opcode_path, 'w', encoding='utf-8') as opcode: + opcode.writelines(output_lines) diff --git a/config/sync-files.py b/config/sync-files.py index e667907b12c..9645d42f1e5 100644 --- a/config/sync-files.py +++ b/config/sync-files.py @@ -59,21 +59,32 @@ def file_checksum(filename): return hashlib.sha1(file_handle.read()).hexdigest() def check_group(group_name, files, master_file_picker, emit_error): - checksums = {file_checksum(f) for f in files} - - if len(checksums) == 1: + extant_files = [f for f in files if path.isfile(f)] + if len(extant_files) == 0: + emit_error(__file__, 0, "No files found from group '" + group_name + "'.") + emit_error(__file__, 0, + "Create one of the following files, and then run this script with " + "the --latest switch to sync it to the other file locations.") + for filename in files: + emit_error(__file__, 0, " " + filename) return - master_file = master_file_picker(files) + checksums = {file_checksum(f) for f in extant_files} + + if len(checksums) == 1 and len(extant_files) == len(files): + # All files are present and identical. + return + + master_file = master_file_picker(extant_files) if master_file is None: emit_error(__file__, 0, "Files from group '"+ group_name +"' not in sync.") emit_error(__file__, 0, "Run this script with a file-name argument among the " "following to overwrite the remaining files with the contents " - "of that file or run with the --latest switch to update each " + "of that file, or run with the --latest switch to update each " "group of files from the most recently modified file in the group.") - for filename in files: + for filename in extant_files: emit_error(__file__, 0, " " + filename) else: print(" Syncing others from", master_file) @@ -81,7 +92,8 @@ def check_group(group_name, files, master_file_picker, emit_error): if filename == master_file: continue print(" " + filename) - os.replace(filename, filename + '~') + if path.isfile(filename): + os.replace(filename, filename + '~') shutil.copy(master_file, filename) print(" Backups written with '~' appended to file names") diff --git a/cpp/autobuilder/.gitignore b/cpp/autobuilder/.gitignore new file mode 100644 index 00000000000..f81ecc73dff --- /dev/null +++ b/cpp/autobuilder/.gitignore @@ -0,0 +1,13 @@ +obj/ +TestResults/ +*.manifest +*.pdb +*.suo +*.mdb +*.vsmdi +csharp.log +**/bin/Debug +**/bin/Release +*.tlog +.vs +*.user \ No newline at end of file diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs new file mode 100644 index 00000000000..87390b7bf8f --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -0,0 +1,296 @@ +using Xunit; +using Semmle.Autobuild.Shared; +using System.Collections.Generic; +using System; +using System.Linq; +using Microsoft.Build.Construction; +using System.Xml; + +namespace Semmle.Autobuild.Cpp.Tests +{ + /// + /// Test class to script Autobuilder scenarios. + /// For most methods, it uses two fields: + /// - an IList to capture the the arguments passed to it + /// - an IDictionary of possible return values. + /// + class TestActions : IBuildActions + { + /// + /// List of strings passed to FileDelete. + /// + public IList FileDeleteIn = new List(); + + void IBuildActions.FileDelete(string file) + { + FileDeleteIn.Add(file); + } + + public IList FileExistsIn = new List(); + public IDictionary FileExists = new Dictionary(); + + bool IBuildActions.FileExists(string file) + { + FileExistsIn.Add(file); + if (FileExists.TryGetValue(file, out var ret)) + return ret; + if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret)) + return ret; + throw new ArgumentException("Missing FileExists " + file); + } + + public IList RunProcessIn = new List(); + public IDictionary RunProcess = new Dictionary(); + public IDictionary RunProcessOut = new Dictionary(); + public IDictionary RunProcessWorkingDirectory = new Dictionary(); + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + if (RunProcessOut.TryGetValue(pattern, out var str)) + stdOut = str.Split("\n"); + else + throw new ArgumentException("Missing RunProcessOut " + pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + public IList DirectoryDeleteIn = new List(); + + void IBuildActions.DirectoryDelete(string dir, bool recursive) + { + DirectoryDeleteIn.Add(dir); + } + + public IDictionary DirectoryExists = new Dictionary(); + public IList DirectoryExistsIn = new List(); + + bool IBuildActions.DirectoryExists(string dir) + { + DirectoryExistsIn.Add(dir); + if (DirectoryExists.TryGetValue(dir, out var ret)) + return ret; + throw new ArgumentException("Missing DirectoryExists " + dir); + } + + public IDictionary GetEnvironmentVariable = new Dictionary(); + + string? IBuildActions.GetEnvironmentVariable(string name) + { + if (GetEnvironmentVariable.TryGetValue(name, out var ret)) + return ret; + throw new ArgumentException("Missing GetEnvironmentVariable " + name); + } + + public string GetCurrentDirectory = ""; + + string IBuildActions.GetCurrentDirectory() + { + return GetCurrentDirectory; + } + + public IDictionary EnumerateFiles = new Dictionary(); + + IEnumerable IBuildActions.EnumerateFiles(string dir) + { + if (EnumerateFiles.TryGetValue(dir, out var str)) + return str.Split("\n"); + throw new ArgumentException("Missing EnumerateFiles " + dir); + } + + public IDictionary EnumerateDirectories = new Dictionary(); + + IEnumerable IBuildActions.EnumerateDirectories(string dir) + { + if (EnumerateDirectories.TryGetValue(dir, out var str)) + return string.IsNullOrEmpty(str) ? Enumerable.Empty() : str.Split("\n"); + throw new ArgumentException("Missing EnumerateDirectories " + dir); + } + + public bool IsWindows; + + bool IBuildActions.IsWindows() => IsWindows; + + string IBuildActions.PathCombine(params string[] parts) + { + return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); + } + + string IBuildActions.GetFullPath(string path) => path; + + void IBuildActions.WriteAllText(string filename, string contents) + { + } + + public IDictionary LoadXml = new Dictionary(); + XmlDocument IBuildActions.LoadXml(string filename) + { + if (LoadXml.TryGetValue(filename, out var xml)) + return xml; + throw new ArgumentException("Missing LoadXml " + filename); + } + + public string EnvironmentExpandEnvironmentVariables(string s) + { + foreach (var kvp in GetEnvironmentVariable) + s = s.Replace($"%{kvp.Key}%", kvp.Value); + return s; + } + } + + /// + /// A fake solution to build. + /// + class TestSolution : ISolution + { + public IEnumerable Configurations => throw new NotImplementedException(); + + public string DefaultConfigurationName => "Release"; + + public string DefaultPlatformName => "x86"; + + public string FullPath { get; set; } + + public Version ToolsVersion => new Version("14.0"); + + public IEnumerable IncludedProjects => throw new NotImplementedException(); + + public TestSolution(string path) + { + FullPath = path; + } + } + + public class BuildScriptTests + { + TestActions Actions = new TestActions(); + + // Records the arguments passed to StartCallback. + IList StartCallbackIn = new List(); + + void StartCallback(string s, bool silent) + { + StartCallbackIn.Add(s); + } + + // Records the arguments passed to EndCallback + IList EndCallbackIn = new List(); + IList EndCallbackReturn = new List(); + + void EndCallback(int ret, string s, bool silent) + { + EndCallbackReturn.Add(ret); + EndCallbackIn.Add(s); + } + + CppAutobuilder CreateAutoBuilder(bool isWindows, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, + string cwd = @"C:\Project") + { + string codeqlUpperLanguage = Language.Cpp.UpperCaseName; + Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; + Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; + Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; + Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; + Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; + Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; + Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; + Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; + Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; + Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; + Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; + Actions.GetCurrentDirectory = cwd; + Actions.IsWindows = isWindows; + + var options = new AutobuildOptions(Actions, Language.Cpp); + return new CppAutobuilder(Actions, options); + } + + void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) + { + Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback)); + + // Check expected commands actually ran + Assert.Equal(commandsRun, StartCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackReturn.Count); + + var action = Actions.RunProcess.GetEnumerator(); + for (int cmd = 0; cmd < commandsRun; ++cmd) + { + Assert.True(action.MoveNext()); + + Assert.Equal(action.Current.Key, StartCallbackIn[cmd]); + Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]); + } + } + + + [Fact] + public void TestDefaultCppAutobuilder() + { + Actions.EnumerateFiles[@"C:\Project"] = ""; + Actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var script = autobuilder.GetBuildScript(); + + // Fails due to no solutions present. + Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); + } + + [Fact] + public void TestCppAutobuilderSuccess() + { + Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; + Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; + Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; + Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; + Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; + Actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var solution = new TestSolution(@"C:\Project\test.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(solution); + TestAutobuilderScript(autobuilder, 0, 2); + } + } +} diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj new file mode 100644 index 00000000000..204b6418299 --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj @@ -0,0 +1,25 @@ + + + + Exe + netcoreapp3.0 + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs new file mode 100644 index 00000000000..44c34656a2a --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs @@ -0,0 +1,23 @@ +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.Cpp +{ + public class CppAutobuilder : Autobuilder + { + public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + if (Options.BuildCommand != null) + return new BuildCommandRule((_, f) => f(null)).Analyse(this, false); + + return + // First try MSBuild + new MsBuildRule().Analyse(this, true) | + // Then look for a script that might be a build script + (() => new BuildCommandAutoRule((_, f) => f(null)).Analyse(this, true)) | + // All attempts failed: print message + AutobuildFailure(); + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/Program.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs similarity index 72% rename from csharp/autobuilder/Semmle.Autobuild/Program.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs index e4bccb0e626..3f4627c53d5 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Program.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs @@ -1,6 +1,7 @@ using System; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Cpp { class Program { @@ -10,11 +11,11 @@ namespace Semmle.Autobuild try { var actions = SystemBuildActions.Instance; - var options = new AutobuildOptions(actions); + var options = new AutobuildOptions(actions, Language.Cpp); try { - Console.WriteLine($"Semmle autobuilder for {options.Language}"); - var builder = new Autobuilder(actions, options); + Console.WriteLine("CodeQL C++ autobuilder"); + var builder = new CppAutobuilder(actions, options); return builder.AttemptBuild(); } catch(InvalidEnvironmentException ex) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs index 778d6305fc5..2d14b0e909d 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild.Tests")] +[assembly: AssemblyTitle("Semmle.Autobuild.Cpp")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Semmle.Extraction.Tests")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C++")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj new file mode 100644 index 00000000000..43e958183ea --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj @@ -0,0 +1,28 @@ + + + + netcoreapp3.0 + Semmle.Autobuild.Cpp + Semmle.Autobuild.Cpp + + Exe + + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + + + + + + + + + diff --git a/cpp/ql/src/Documentation/CaptionedComments.qll b/cpp/ql/src/Documentation/CaptionedComments.qll index c955f97a029..0ccd678e79f 100644 --- a/cpp/ql/src/Documentation/CaptionedComments.qll +++ b/cpp/ql/src/Documentation/CaptionedComments.qll @@ -4,6 +4,10 @@ import cpp +/** + * Gets a string representation of the comment `c` containing the caption 'TODO' or 'FIXME'. + * If `c` spans multiple lines, all lines after the first are abbreviated as [...]. + */ string getCommentTextCaptioned(Comment c, string caption) { (caption = "TODO" or caption = "FIXME") and exists( diff --git a/cpp/ql/src/Documentation/CommentedOutCode.qll b/cpp/ql/src/Documentation/CommentedOutCode.qll index 14e74b0a20c..172474bbe29 100644 --- a/cpp/ql/src/Documentation/CommentedOutCode.qll +++ b/cpp/ql/src/Documentation/CommentedOutCode.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for identifying C/C++ comments that look like code. + */ + import cpp /** @@ -137,8 +141,14 @@ class CommentBlock extends Comment { ) } + /** + * Gets the last comment associated with this comment block. + */ Comment lastComment() { result = this.getComment(max(int i | exists(this.getComment(i)))) } + /** + * Gets the contents of the `i`'th comment associated with this comment block. + */ string getLine(int i) { this instanceof CStyleComment and result = this.getContents().regexpCapture("(?s)/\\*+(.*)\\*+/", 1).splitAt("\n", i) @@ -146,14 +156,24 @@ class CommentBlock extends Comment { this instanceof CppStyleComment and result = this.getComment(i).getContents().suffix(2) } + /** + * Gets the number of lines in the comments associated with this comment block. + */ int numLines() { result = strictcount(int i, string line | line = this.getLine(i) and line.trim() != "") } + /** + * Gets the number of lines that look like code in the comments associated with this comment block. + */ int numCodeLines() { result = strictcount(int i, string line | line = this.getLine(i) and looksLikeCode(line)) } + /** + * Holds if the comment block is a C-style comment, and each + * comment line starts with a *. + */ predicate isDocumentation() { // If a C-style comment starts each line with a *, then it's // probably documentation rather than code. @@ -161,6 +181,12 @@ class CommentBlock extends Comment { forex(int i | i in [1 .. this.numLines() - 1] | this.getLine(i).trim().matches("*%")) } + /** + * Holds if this comment block looks like code that has been commented out. Specifically: + * 1. It does not look like documentation (see `isDocumentation`). + * 2. It is not in a header file without any declaration entries or top level declarations. + * 3. More than half of the lines in the comment block look like code. + */ predicate isCommentedOutCode() { not this.isDocumentation() and not this.getFile().(HeaderFile).noTopLevelCode() and diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql index b53cb1d50b3..074c82bc03b 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql @@ -15,6 +15,15 @@ import cpp import semmle.code.cpp.models.implementations.Strcpy import semmle.code.cpp.dataflow.DataFlow +/** + * A string copy function that returns a string, rather than an error code (for + * example, `strcpy` returns a string, whereas `strcpy_s` returns an error + * code). + */ +class InterestingStrcpyFunction extends StrcpyFunction { + InterestingStrcpyFunction() { getType().getUnspecifiedType() instanceof PointerType } +} + predicate isBoolean(Expr e1) { exists(Type t1 | t1 = e1.getType() and @@ -25,12 +34,12 @@ predicate isBoolean(Expr e1) { predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) { DataFlow::localExprFlow(func, expr1) and isBoolean(expr1.getConversion*()) and - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and msg = "Return value of " + func.getTarget().getName() + " used as a Boolean." } predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) { - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and ( ( // it is being used in an equality or logical operation diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql index 6ba835acbdc..65ba665dff2 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql @@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering class NullInstruction extends ConstantValueInstruction { NullInstruction() { this.getValue() = "0" and - this.getResultType().getUnspecifiedType() instanceof PointerType + this.getResultIRType() instanceof IRAddressType } } @@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) { bool = any(ConvertInstruction convert | checked = convert.getUnary() and - convert.getResultType() instanceof BoolType and - checked.getResultType() instanceof PointerType + convert.getResultIRType() instanceof IRBooleanType and + checked.getResultIRType() instanceof IRAddressType ) } diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index b65d256f45c..6f3f4d43e9a 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -6,29 +6,50 @@ import cpp -// True if function was ()-declared, but not (void)-declared or K&R-defined +/** + * Holds if `fde` has a parameter declaration that's clear on the minimum + * number of parameters. This is essentially true for everything except + * `()`-declarations. + */ +private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) { + fde.hasVoidParamList() + or + fde.getNumberOfParameters() > 0 + or + fde.isDefinition() +} + +/* Holds if function was ()-declared, but not (void)-declared or K&R-defined. */ private predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + not hasDefiniteNumberOfParameters(fde) ) } -// True if this file (or header) was compiled as a C file +/* Holds if this file (or header) was compiled as a C file. */ private predicate isCompiledAsC(File f) { f.compiledAsC() or exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f) } +/** Holds if `fc` is a call to `f` with too few arguments. */ predicate tooFewArguments(FunctionCall fc, Function f) { f = fc.getTarget() and not f.isVarargs() and not f instanceof BuiltInFunction and + // This query should only have results on C (not C++) functions that have a + // `()` parameter list somewhere. If it has results on other functions, then + // it's probably because the extractor only saw a partial compilation. hasZeroParamDecl(f) and isCompiledAsC(f.getFile()) and - // There is an explicit declaration of the function whose parameter count is larger - // than the number of call arguments - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + // Produce an alert when all declarations that are authoritative on the + // parameter count specify a parameter count larger than the number of call + // arguments. + forex(FunctionDeclarationEntry fde | + fde = f.getADeclarationEntry() and + hasDefiniteNumberOfParameters(fde) + | fde.getNumberOfParameters() > fc.getNumberOfArguments() ) } diff --git a/cpp/ql/src/Metrics/History/HChurn.ql b/cpp/ql/src/Metrics/History/HChurn.ql deleted file mode 100644 index 7ff156b5300..00000000000 --- a/cpp/ql/src/Metrics/History/HChurn.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Churned lines per file - * @description Number of churned lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-churn - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentChurnForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesAdded.ql b/cpp/ql/src/Metrics/History/HLinesAdded.ql deleted file mode 100644 index ce03c5b4190..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesAdded.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Added lines per file - * @description Number of added lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-added - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentAdditionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesDeleted.ql b/cpp/ql/src/Metrics/History/HLinesDeleted.ql deleted file mode 100644 index 3d8ce78b6c4..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesDeleted.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Deleted lines per file - * @description Number of deleted lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-deleted - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentDeletionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql deleted file mode 100644 index 2d8f1f382c3..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Number of authors - * @description Number of distinct authors for each file. - * @kind treemap - * @id cpp/historical-number-of-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Author author | author.getAnEditedFile() = f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfChanges.ql deleted file mode 100644 index 451dc575636..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Number of file-level changes - * @description The number of file-level changes made (by version - * control history). - * @kind treemap - * @id cpp/historical-number-of-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Commit svn | f = svn.getAnAffectedFile() and not artificialChange(svn)) diff --git a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql deleted file mode 100644 index ecd5c4ccb0d..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @name Number of co-committed files - * @description The average number of other files that are touched - * whenever a file is affected by a commit. - * @kind treemap - * @id cpp/historical-number-of-co-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, avg(Commit commit | commit.getAnAffectedFile() = f | committedFiles(commit) - 1) diff --git a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql deleted file mode 100644 index fe98e66964e..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @name Number of re-commits for each file - * @description A re-commit is taken to mean a commit to a file that - * was touched less than five days ago. - * @kind treemap - * @id cpp/historical-number-of-re-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate inRange(Commit first, Commit second) { - first.getAnAffectedFile() = second.getAnAffectedFile() and - first != second and - exists(int n | - n = first.getDate().daysTo(second.getDate()) and - n >= 0 and - n < 5 - ) -} - -int recommitsForFile(File f) { - result = - count(Commit recommit | - f = recommit.getAnAffectedFile() and - exists(Commit prev | inRange(prev, recommit)) - ) -} - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, recommitsForFile(f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql deleted file mode 100644 index 7f40c8706d9..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Number of recent authors - * @description Number of distinct authors that have recently made - * changes. - * @kind treemap - * @id cpp/historical-number-of-recent-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, - count(Author author | - exists(Commit e | - e = author.getACommit() and - f = e.getAnAffectedFile() and - e.daysToNow() <= 180 and - not artificialChange(e) - ) - ) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql deleted file mode 100644 index 751449eb5aa..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @name Recently changed files - * @description Number of files recently edited. - * @kind treemap - * @id cpp/historical-number-of-recent-changed-files - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where - exists(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, 1 diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql deleted file mode 100644 index 886e8da6ca8..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Recent changes - * @description Number of recent commits to this file. - * @kind treemap - * @id cpp/historical-number-of-recent-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - count(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 91ccc5c4d40..b64091263e0 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql index 96cffdb024b..d38f3eb24c2 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string-through-global * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 3f6ff63635e..af64a1789c3 100644 --- a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -18,7 +18,7 @@ abstract class InsecureCryptoSpec extends Locatable { } Function getAnInsecureFunction() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getACallToThisFunction()) } @@ -33,7 +33,7 @@ class InsecureFunctionCall extends InsecureCryptoSpec, FunctionCall { } Macro getAnInsecureMacro() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getAnInvocation()) } diff --git a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls index 27bff98ea5d..f811010a26a 100644 --- a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls +++ b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-cpp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index 2036584e44c..1032261fb94 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -2,13 +2,10 @@ - qlpack: codeql-cpp - apply: lgtm-selectors.yml from: codeql-suite-helpers -# These queries are infeasible to compute on large projects: +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp +# These are only for IDE use. - exclude: - query path: - - Security/CWE/CWE-497/ExposedSystemData.ql - - Critical/DescriptorMayNotBeClosed.ql - - Critical/DescriptorNeverClosed.ql - - Critical/FileMayNotBeClosed.ql - - Critical/FileNeverClosed.ql - - Critical/MemoryMayNotBeFreed.ql - - Critical/MemoryNeverFreed.ql + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references diff --git a/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls new file mode 100644 index 00000000000..297f46bc752 --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls @@ -0,0 +1,6 @@ +- description: Security-and-quality queries for C and C++ +- qlpack: codeql-cpp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls new file mode 100644 index 00000000000..fa69559add0 --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -0,0 +1,6 @@ +- description: Security-extended queries for C and C++ +- qlpack: codeql-cpp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/exclude-slow-queries.yml b/cpp/ql/src/codeql-suites/exclude-slow-queries.yml new file mode 100644 index 00000000000..a1a4ced9c7d --- /dev/null +++ b/cpp/ql/src/codeql-suites/exclude-slow-queries.yml @@ -0,0 +1,11 @@ +- description: C/C++ queries which are infeasible to compute on large projects +# These queries are infeasible to compute on large projects: +- exclude: + query path: + - Security/CWE/CWE-497/ExposedSystemData.ql + - Critical/DescriptorMayNotBeClosed.ql + - Critical/DescriptorNeverClosed.ql + - Critical/FileMayNotBeClosed.ql + - Critical/FileNeverClosed.ql + - Critical/MemoryMayNotBeFreed.ql + - Critical/MemoryNeverFreed.ql diff --git a/cpp/ql/src/cpp.qll b/cpp/ql/src/cpp.qll index 78fde101a42..a989c9a6c9d 100644 --- a/cpp/ql/src/cpp.qll +++ b/cpp/ql/src/cpp.qll @@ -32,6 +32,7 @@ import semmle.code.cpp.Enum import semmle.code.cpp.Member import semmle.code.cpp.Field import semmle.code.cpp.Function +import semmle.code.cpp.MemberFunction import semmle.code.cpp.Parameter import semmle.code.cpp.Variable import semmle.code.cpp.Initializer diff --git a/cpp/ql/src/default.qll b/cpp/ql/src/default.qll index 4996ace8452..6bc0f1b009d 100644 --- a/cpp/ql/src/default.qll +++ b/cpp/ql/src/default.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: use `import cpp` instead of `import default`. + * + * Provides classes and predicates for working with C/C++ code. + */ + import cpp diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/src/definitions.qll index 4af638e07b9..b42903953b6 100644 --- a/cpp/ql/src/definitions.qll +++ b/cpp/ql/src/definitions.qll @@ -132,6 +132,7 @@ private predicate constructorCallTypeMention(ConstructorCall cc, TypeMention tm) * - `"X"` for macro accesses * - `"I"` for import / include directives */ +cached Top definitionOf(Top e, string kind) { ( // call -> function called @@ -213,3 +214,11 @@ Top definitionOf(Top e, string kind) { // later on. strictcount(result.getLocation()) < 10 } + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll index 8388511932e..39db446e3d3 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll @@ -20,7 +20,7 @@ import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.models.interfaces.Allocation -private import semmle.code.cpp.rangeanalysis.RangeUtils +private import experimental.semmle.code.cpp.rangeanalysis.RangeUtils private newtype TLength = TZeroLength() or diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll similarity index 89% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll index fe0e211087c..bdd0e39f9b7 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll @@ -8,8 +8,8 @@ private newtype TBound = exists(Instruction i | vn.getAnInstruction() = i and ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType + i.getResultIRType() instanceof IRIntegerType or + i.getResultIRType() instanceof IRAddressType ) and not vn.getAnInstruction() instanceof ConstantInstruction | @@ -68,7 +68,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber { ValueNumberBound() { this = TBoundValueNumber(vn) } - /** Gets the SSA variable that equals this bound. */ + /** Gets an `Instruction` that equals this bound. */ override Instruction getInstruction(int delta) { this = TBoundValueNumber(valueNumber(result)) and delta = 0 } @@ -76,4 +76,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber { override string toString() { result = vn.getExampleInstruction().toString() } override Location getLocation() { result = vn.getLocation() } + + /** Gets the value number that equals this bound. */ + ValueNumber getValueNumber() { result = vn } } diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll new file mode 100644 index 00000000000..a7375f66b66 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll @@ -0,0 +1,105 @@ +/** + * This library proves that a subset of pointer dereferences in a program are + * safe, i.e. in-bounds. + * It does so by first defining what a pointer dereference is (on the IR + * `Instruction` level), and then using the array length analysis and the range + * analysis together to prove that some of these pointer dereferences are safe. + * + * The analysis is soundy, i.e. it is sound if no undefined behaviour is present + * in the program. + * Furthermore, it crucially depends on the soundiness of the range analysis and + * the array length analysis. + */ + +import cpp +private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis +private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis + +/** + * Gets the instruction that computes the address of memory that `i` accesses. + * Only holds if `i` dereferences a pointer, not when the computation of the + * memory address is constant, or if the address of a local variable is loaded/stored to. + */ +private Instruction getMemoryAddressInstruction(Instruction i) { + ( + result = i.(FieldAddressInstruction).getObjectAddress() or + result = i.(LoadInstruction).getSourceAddress() or + result = i.(StoreInstruction).getDestinationAddress() + ) and + not result instanceof FieldAddressInstruction and + not result instanceof VariableAddressInstruction and + not result instanceof ConstantValueInstruction +} + +/** + * All instructions that dereference a pointer. + */ +class PointerDereferenceInstruction extends Instruction { + PointerDereferenceInstruction() { exists(getMemoryAddressInstruction(this)) } + + Instruction getAddress() { result = getMemoryAddressInstruction(this) } +} + +/** + * Holds if `ptrDeref` can be proven to always access allocated memory. + */ +predicate inBounds(PointerDereferenceInstruction ptrDeref) { + exists(Length length, int lengthDelta, Offset offset, int offsetDelta | + knownArrayLength(ptrDeref.getAddress(), length, lengthDelta, offset, offsetDelta) and + // lower bound - note that we treat a pointer that accesses an array of + // length 0 as on upper-bound violation, but not as a lower-bound violation + ( + offset instanceof ZeroOffset and + offsetDelta >= 0 + or + offset instanceof OpOffset and + exists(int lowerBoundDelta | + boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), lowerBoundDelta, + /*upper*/ false, _) and + lowerBoundDelta + offsetDelta >= 0 + ) + ) and + // upper bound + ( + // both offset and length are only integers + length instanceof ZeroLength and + offset instanceof ZeroOffset and + offsetDelta < lengthDelta + or + exists(int lengthBound | + // array length is variable+integer, and there's a fixed (integer-only) + // lower bound on the variable, so we can guarantee this access is always in-bounds + length instanceof VNLength and + offset instanceof ZeroOffset and + boundedInstruction(length.(VNLength).getInstruction(), any(ZeroBound b), lengthBound, + /* upper*/ false, _) and + offsetDelta < lengthBound + lengthDelta + ) + or + exists(int offsetBoundDelta | + length instanceof ZeroLength and + offset instanceof OpOffset and + boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), offsetBoundDelta, + /* upper */ true, _) and + // offset <= offsetBoundDelta, so offset + offsetDelta <= offsetDelta + offsetBoundDelta + // Thus, in-bounds if offsetDelta + offsetBoundDelta < lengthDelta + // as we have length instanceof ZeroLength + offsetDelta + offsetBoundDelta < lengthDelta + ) + or + exists(ValueNumberBound b, int offsetBoundDelta | + length instanceof VNLength and + offset instanceof OpOffset and + b.getValueNumber() = length.(VNLength).getValueNumber() and + // It holds that offset <= length + offsetBoundDelta + boundedOperand(offset.(OpOffset).getOperand(), b, offsetBoundDelta, /*upper*/ true, _) and + // it also holds that + offsetDelta < lengthDelta - offsetBoundDelta + // taking both inequalities together we get + // offset <= length + offsetBoundDelta + // => offset + offsetDelta <= length + offsetBoundDelta + offsetDelta < length + offsetBoundDelta + lengthDelta - offsetBoundDelta + // as required + ) + ) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll similarity index 97% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll index a79df3c37d7..4a5bef36b20 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll @@ -244,14 +244,14 @@ class CondReason extends Reason, TCondReason { /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 +private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) { + typ.isSigned() and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ.isUnsigned() and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + typ.isSigned() and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767 or - typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 + typ.isUnsigned() and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535 } /** @@ -260,14 +260,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { private class NarrowingCastInstruction extends ConvertInstruction { NarrowingCastInstruction() { not this instanceof SafeCastInstruction and - typeBound(getResultType(), _, _) + typeBound(getResultIRType(), _, _) } /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(getResultType(), result, _) } + int getLowerBound() { typeBound(getResultIRType(), result, _) } /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(getResultType(), _, result) } + int getUpperBound() { typeBound(getResultIRType(), _, result) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll similarity index 90% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll index ee790404559..bffd08fbe52 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll @@ -86,15 +86,15 @@ predicate backEdge(PhiInstruction phi, PhiInputOperand op) { * range analysis. */ pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and +private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) { + fromtyp.getByteSize() < totyp.getByteSize() and ( fromtyp.isUnsigned() or totyp.isSigned() ) or - fromtyp.getSize() <= totyp.getSize() and + fromtyp.getByteSize() <= totyp.getByteSize() and ( fromtyp.isSigned() and totyp.isSigned() @@ -109,8 +109,8 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { */ class PtrToPtrCastInstruction extends ConvertInstruction { PtrToPtrCastInstruction() { - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType + getResultIRType() instanceof IRAddressType and + getUnary().getResultIRType() instanceof IRAddressType } } @@ -119,7 +119,7 @@ class PtrToPtrCastInstruction extends ConvertInstruction { * that cannot overflow or underflow. */ class SafeIntCastInstruction extends ConvertInstruction { - SafeIntCastInstruction() { safeCast(getUnary().getResultType(), getResultType()) } + SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll similarity index 97% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index ca641f826ef..0bd73105cc5 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll @@ -278,8 +278,6 @@ private predicate unknownSign(Instruction i) { // non-positive, non-zero}, which would mean that the representation of the sign of an unknown // value would be the empty set. ( - i instanceof UnmodeledDefinitionInstruction - or i instanceof UninitializedInstruction or i instanceof InitializeParameterInstruction @@ -471,7 +469,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType().(IntegralType).isUnsigned() + i.getResultIRType().(IRIntegerType).isUnsigned() ) and ( unknownSign(i) @@ -479,9 +477,13 @@ module SignAnalysisCached { exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | i = ci and prior = ci.getUnary() and - (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and ( - if prior.getResultType().(IntegralType).isSigned() + if ci.getResultIRType().(IRIntegerType).isSigned() + then toSigned = true + else toSigned = false + ) and + ( + if prior.getResultIRType().(IRIntegerType).isSigned() then fromSigned = true else fromSigned = false ) and @@ -514,11 +516,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType).isSigned() and + i.getResultIRType().(IRIntegerType).isSigned() and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType).isSigned() and + not i.getResultIRType().(IRIntegerType).isSigned() and result = s1.urshift(s2) ) or diff --git a/cpp/ql/src/external/CodeDuplication.qll b/cpp/ql/src/external/CodeDuplication.qll index 2f4fd0d05da..4548e0be85e 100644 --- a/cpp/ql/src/external/CodeDuplication.qll +++ b/cpp/ql/src/external/CodeDuplication.qll @@ -1,3 +1,5 @@ +/** Provides classes for detecting duplicate or similar code. */ + import cpp private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } @@ -8,9 +10,12 @@ private predicate tokenLocation(string path, int sl, int sc, int ec, int el, Cop tokens(copy, index, sl, sc, ec, el) } +/** A token block used for detection of duplicate and similar code. */ class Copy extends @duplication_or_similarity { + /** Gets the index of the last token in this block. */ private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } + /** Gets the index of the token in this block starting at the location `loc`, if any. */ int tokenStartingAt(Location loc) { exists(string filepath, int startline, int startcol | loc.hasLocationInfo(filepath, startline, startcol, _, _) and @@ -18,6 +23,7 @@ class Copy extends @duplication_or_similarity { ) } + /** Gets the index of the token in this block ending at the location `loc`, if any. */ int tokenEndingAt(Location loc) { exists(string filepath, int endline, int endcol | loc.hasLocationInfo(filepath, _, _, endline, endcol) and @@ -25,24 +31,38 @@ class Copy extends @duplication_or_similarity { ) } + /** Gets the line on which the first token in this block starts. */ int sourceStartLine() { tokens(this, 0, result, _, _, _) } + /** Gets the column on which the first token in this block starts. */ int sourceStartColumn() { tokens(this, 0, _, result, _, _) } + /** Gets the line on which the last token in this block ends. */ int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) } + /** Gets the column on which the last token in this block ends. */ int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) } + /** Gets the number of lines containing at least (part of) one token in this block. */ int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } + /** Gets an opaque identifier for the equivalence class of this block. */ int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } + /** Gets the source file in which this block appears. */ File sourceFile() { exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | name.replaceAll("\\", "/") = relativePath(result) ) } + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { @@ -53,25 +73,30 @@ class Copy extends @duplication_or_similarity { endcolumn = sourceEndColumn() } + /** Gets a textual representation of this element. */ string toString() { none() } } +/** A block of duplicated code. */ class DuplicateBlock extends Copy, @duplication { override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } } +/** A block of similar code. */ class SimilarBlock extends Copy, @similarity { override string toString() { result = "Similar code: " + sourceLines() + " almost duplicated lines." } } +/** Gets a function with a body and a location. */ FunctionDeclarationEntry sourceMethod() { result.isDefinition() and exists(result.getLocation()) and numlines(unresolveElement(result.getFunction()), _, _, _) } +/** Gets the number of member functions in `c` with a body and a location. */ int numberOfSourceMethods(Class c) { result = count(FunctionDeclarationEntry m | @@ -108,6 +133,10 @@ private predicate duplicateStatement( ) } +/** + * Holds if `m1` is a function with `total` lines, and `m2` is a function + * that has `duplicate` lines in common with `m1`. + */ predicate duplicateStatements( FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total ) { @@ -115,13 +144,16 @@ predicate duplicateStatements( total = strictcount(statementInMethod(m1)) } -/** - * Find pairs of methods are identical - */ +/** Holds if `m` and other are identical functions. */ predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) { exists(int total | duplicateStatements(m, other, total, total)) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is similar to a line somewhere else. + */ predicate similarLines(File f, int line) { exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) } @@ -152,6 +184,7 @@ private predicate similarLinesCoveredFiles(File f, File otherFile) { ) } +/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | similarLinesCoveredFiles(f, otherFile) and @@ -166,6 +199,11 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is duplicated by a line somewhere else. + */ predicate duplicateLines(File f, int line) { exists(DuplicateBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] @@ -182,6 +220,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | exists(int coveredApprox | @@ -206,6 +245,7 @@ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** Holds if most of `f` (`percent`%) is similar to `other`. */ predicate similarFiles(File f, File other, int percent) { exists(int covered, int total | similarLinesCovered(f, covered, other) and @@ -216,6 +256,7 @@ predicate similarFiles(File f, File other, int percent) { not duplicateFiles(f, other, _) } +/** Holds if most of `f` (`percent`%) is duplicated by `other`. */ predicate duplicateFiles(File f, File other, int percent) { exists(int covered, int total | duplicateLinesCovered(f, covered, other) and @@ -225,6 +266,10 @@ predicate duplicateFiles(File f, File other, int percent) { ) } +/** + * Holds if most member functions of `c` (`numDup` out of `total`) are + * duplicates of member functions in `other`. + */ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { numDup = strictcount(FunctionDeclarationEntry m1 | @@ -240,6 +285,11 @@ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) (numDup * 100) / total > 80 } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. Provides the human-readable `message` to describe the amount of + * duplication. + */ predicate mostlyDuplicateClass(Class c, Class other, string message) { exists(int numDup, int total | mostlyDuplicateClassBase(c, other, numDup, total) and @@ -264,12 +314,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } +/** Holds if `f` and `other` are similar or duplicates. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. + */ predicate classLevelDuplication(Class c, Class other) { mostlyDuplicateClass(c, other, _) } +/** + * Holds if `line` in `f` should be allowed to be duplicated. This is the case + * for `#include` directives. + */ predicate whitelistedLineForDuplication(File f, int line) { exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line) } diff --git a/cpp/ql/src/external/DefectFilter.qll b/cpp/ql/src/external/DefectFilter.qll index da63893b8bb..675f3b25faa 100644 --- a/cpp/ql/src/external/DefectFilter.qll +++ b/cpp/ql/src/external/DefectFilter.qll @@ -1,31 +1,52 @@ +/** Provides a class for working with defect query results stored in dashboard databases. */ + import cpp +/** + * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, + * such that `message` is the associated message and the location of the result spans + * column `startcolumn` of line `startline` to column `endcolumn` of line `endline` + * in file `filepath`. + * + * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ external predicate defectResults( int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, string message ); +/** + * A defect query result stored in a dashboard database. + */ class DefectResult extends int { DefectResult() { defectResults(this, _, _, _, _, _, _, _) } + /** Gets the path of the query that reported the result. */ string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) } + /** Gets the file in which this query result was reported. */ File getFile() { exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path ) } + /** Gets the line on which the location of this query result starts. */ int getStartLine() { defectResults(this, _, _, result, _, _, _, _) } + /** Gets the column on which the location of this query result starts. */ int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) } + /** Gets the line on which the location of this query result ends. */ int getEndLine() { defectResults(this, _, _, _, _, result, _, _) } + /** Gets the column on which the location of this query result ends. */ int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) } + /** Gets the message associated with this query result. */ string getMessage() { defectResults(this, _, _, _, _, _, _, result) } + /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + diff --git a/cpp/ql/src/external/ExternalArtifact.qll b/cpp/ql/src/external/ExternalArtifact.qll index 94fa0d7e31a..abbc96a7b47 100644 --- a/cpp/ql/src/external/ExternalArtifact.qll +++ b/cpp/ql/src/external/ExternalArtifact.qll @@ -1,26 +1,45 @@ +/** + * Provides classes for working with external data. + */ + import cpp +/** + * An external data item. + */ class ExternalData extends @externalDataElement { + /** Gets the path of the file this data was loaded from. */ string getDataPath() { externalData(this, result, _, _) } + /** + * Gets the path of the file this data was loaded from, with its + * extension replaced by `.ql`. + */ string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + /** Gets the number of fields in this data item. */ int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } - string getField(int index) { externalData(this, _, index, result) } + /** Gets the value of the `i`th field of this data item. */ + string getField(int i) { externalData(this, _, i, result) } - int getFieldAsInt(int index) { result = getField(index).toInt() } + /** Gets the integer value of the `i`th field of this data item. */ + int getFieldAsInt(int i) { result = getField(i).toInt() } - float getFieldAsFloat(int index) { result = getField(index).toFloat() } + /** Gets the floating-point value of the `i`th field of this data item. */ + float getFieldAsFloat(int i) { result = getField(i).toFloat() } - date getFieldAsDate(int index) { result = getField(index).toDate() } + /** Gets the value of the `i`th field of this data item, interpreted as a date. */ + date getFieldAsDate(int i) { result = getField(i).toDate() } + /** Gets a textual representation of this data item. */ string toString() { result = getQueryPath() + ": " + buildTupleString(0) } - private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) + /** Gets a textual representation of this data item, starting with the `n`th field. */ + private string buildTupleString(int n) { + n = getNumFields() - 1 and result = getField(n) or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) + n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1) } } @@ -33,7 +52,9 @@ class DefectExternalData extends ExternalData { this.getNumFields() = 2 } + /** Gets the URL associated with this data item. */ string getURL() { result = getField(0) } + /** Gets the message associated with this data item. */ string getMessage() { result = getField(1) } } diff --git a/cpp/ql/src/external/MetricFilter.qll b/cpp/ql/src/external/MetricFilter.qll index b159b4cad5c..dd9cece78ce 100644 --- a/cpp/ql/src/external/MetricFilter.qll +++ b/cpp/ql/src/external/MetricFilter.qll @@ -1,31 +1,58 @@ +/** Provides a class for working with metric query results stored in dashboard databases. */ + import cpp +/** + * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, + * such that `value` is the reported metric value and the location of the result spans + * column `startcolumn` of line `startline` to column `endcolumn` of line `endline` + * in file `filepath`. + * + * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ external predicate metricResults( int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, float value ); +/** + * A metric query result stored in a dashboard database. + */ class MetricResult extends int { MetricResult() { metricResults(this, _, _, _, _, _, _, _) } + /** Gets the path of the query that reported the result. */ string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) } + /** Gets the file in which this query result was reported. */ File getFile() { exists(string path | metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path ) } + /** Gets the line on which the location of this query result starts. */ int getStartLine() { metricResults(this, _, _, result, _, _, _, _) } + /** Gets the column on which the location of this query result starts. */ int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) } + /** Gets the line on which the location of this query result ends. */ int getEndLine() { metricResults(this, _, _, _, _, result, _, _) } + /** Gets the column on which the location of this query result ends. */ int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) } + /** + * Holds if there is a `Location` entity whose location is the same as + * the location of this query result. + */ predicate hasMatchingLocation() { exists(this.getMatchingLocation()) } + /** + * Gets the `Location` entity whose location is the same as the location + * of this query result. + */ Location getMatchingLocation() { result.getFile() = this.getFile() and result.getStartLine() = this.getStartLine() and @@ -34,8 +61,10 @@ class MetricResult extends int { result.getEndColumn() = this.getEndColumn() } + /** Gets the value associated with this query result. */ float getValue() { metricResults(this, _, _, _, _, _, _, result) } + /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + diff --git a/cpp/ql/src/external/VCS.qll b/cpp/ql/src/external/VCS.qll deleted file mode 100644 index ce36ace56d9..00000000000 --- a/cpp/ql/src/external/VCS.qll +++ /dev/null @@ -1,92 +0,0 @@ -import cpp - -class Commit extends @svnentry { - Commit() { - svnaffectedfiles(this, _, _) and - exists(date svnDate, date snapshotDate | - svnentries(this, _, _, svnDate, _) and - snapshotDate(snapshotDate) and - svnDate <= snapshotDate - ) - } - - string toString() { result = this.getRevisionName() } - - string getRevisionName() { svnentries(this, result, _, _, _) } - - string getAuthor() { svnentries(this, _, result, _, _) } - - date getDate() { svnentries(this, _, _, result, _) } - - int getChangeSize() { svnentries(this, _, _, _, result) } - - string getMessage() { svnentrymsg(this, result) } - - string getAnAffectedFilePath(string action) { - exists(File rawFile | svnaffectedfiles(this, unresolveElement(rawFile), action) | - result = rawFile.getAbsolutePath() - ) - } - - string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) } - - File getAnAffectedFile(string action) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = result.getAbsolutePath() | - svnaffectedfiles(this, unresolveElement(svnFile), action) - ) and - exists(result.getMetrics().getNumberOfLinesOfCode()) - } - - File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) } - - private predicate churnForFile(File f, int added, int deleted) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = f.getAbsolutePath() | - svnchurn(this, unresolveElement(svnFile), added, deleted) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) - } - - int getRecentChurnForFile(File f) { - exists(int added, int deleted | churnForFile(f, added, deleted) and result = added + deleted) - } - - int getRecentAdditionsForFile(File f) { churnForFile(f, result, _) } - - int getRecentDeletionsForFile(File f) { churnForFile(f, _, result) } - - predicate isRecent() { recentCommit(this) } - - int daysToNow() { - exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0) - } -} - -class Author extends string { - Author() { exists(Commit e | this = e.getAuthor()) } - - Commit getACommit() { result.getAuthor() = this } - - File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() } -} - -predicate recentCommit(Commit e) { - exists(date snapshotDate, date commitDate, int days | - snapshotDate(snapshotDate) and - e.getDate() = commitDate and - days = commitDate.daysTo(snapshotDate) and - days >= 0 and - days <= 60 - ) -} - -date firstChange(File f) { - result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin) -} - -predicate firstCommit(Commit e) { - not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate()) -} - -predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 } diff --git a/cpp/ql/src/external/tests/DefectFromSVN.ql b/cpp/ql/src/external/tests/DefectFromSVN.ql deleted file mode 100644 index 64dd69148eb..00000000000 --- a/cpp/ql/src/external/tests/DefectFromSVN.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Defect from SVN - * @description A test case for creating a defect from SVN data. - * @kind problem - * @problem.severity warning - * @tags external-data - * @deprecated - */ - -import cpp -import external.ExternalArtifact -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -predicate maxCommits(int i) { i = max(File f, int j | numCommits(f, j) | j) } - -from File f, int i -where numCommits(f, i) and maxCommits(i) -select f, "This file has " + i + " commits." diff --git a/cpp/ql/src/external/tests/MetricFromSVN.ql b/cpp/ql/src/external/tests/MetricFromSVN.ql deleted file mode 100644 index e81eec18ea5..00000000000 --- a/cpp/ql/src/external/tests/MetricFromSVN.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Metric from SVN - * @description Find number of commits for a file - * @treemap.warnOn lowValues - * @metricType file - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -from File f, int i -where numCommits(f, i) -select f, i diff --git a/cpp/ql/src/filters/RecentDefects.ql b/cpp/ql/src/filters/RecentDefects.ql deleted file mode 100644 index 4b742849fda..00000000000 --- a/cpp/ql/src/filters/RecentDefects.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Filter: exclude results from files that have not recently been - * edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the date of the snapshot. - * @kind problem - * @id cpp/recent-defects-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.DefectFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from DefectResult res -where recent(res.getFile()) -select res, res.getMessage() diff --git a/cpp/ql/src/filters/RecentDefectsForMetric.ql b/cpp/ql/src/filters/RecentDefectsForMetric.ql deleted file mode 100644 index ee057fe71ca..00000000000 --- a/cpp/ql/src/filters/RecentDefectsForMetric.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Metric filter: exclude results from files that have not - * recently been edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the snapshot. - * @kind treemap - * @id cpp/recent-defects-for-metric-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.MetricFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from MetricResult res -where recent(res.getFile()) -select res, res.getValue() diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..1e525d8e2dd --- /dev/null +++ b/cpp/ql/src/localDefinitions.ql @@ -0,0 +1,16 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id cpp/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Top e, Top def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql new file mode 100644 index 00000000000..13ca4dd2561 --- /dev/null +++ b/cpp/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id cpp/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Top e, Top def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/cpp/ql/src/objc.qll b/cpp/ql/src/objc.qll index 4996ace8452..58a9ec50ff7 100644 --- a/cpp/ql/src/objc.qll +++ b/cpp/ql/src/objc.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: Objective C is no longer supported. + * + * Import `cpp` instead of `objc`. + */ + import cpp diff --git a/cpp/ql/src/printAst.ql b/cpp/ql/src/printAst.ql new file mode 100644 index 00000000000..622e5812be1 --- /dev/null +++ b/cpp/ql/src/printAst.ql @@ -0,0 +1,27 @@ +/** + * @name Print AST + * @description Outputs a representation of a file's Abstract Syntax Tree. This + * query is used by the VS Code extension. + * @id cpp/print-ast + * @kind graph + * @tags ide-contextual-queries/print-ast + */ + +import cpp +import semmle.code.cpp.PrintAST +import definitions + +/** + * The source file to generate an AST from. + */ +external string selectedSourceFile(); + +class Cfg extends PrintASTConfiguration { + /** + * Holds if the AST for `func` should be printed. + * Print All functions from the selected file. + */ + override predicate shouldPrintFunction(Function func) { + func.getFile() = getEncodedFile(selectedSourceFile()) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql b/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql new file mode 100644 index 00000000000..6d3c9f48457 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql @@ -0,0 +1,9 @@ +/** + * @name AST Consistency Check + * @description Performs consistency checks on the Abstract Syntax Tree. This query should have no results. + * @kind table + * @id cpp/ast-consistency-check + */ + +import cpp +import CastConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ASTSanity.ql b/cpp/ql/src/semmle/code/cpp/ASTSanity.ql deleted file mode 100644 index aeb05379f8c..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ASTSanity.ql +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @name AST Sanity Check - * @description Performs sanity checks on the Abstract Syntax Tree. This query should have no results. - * @kind table - * @id cpp/ast-sanity-check - */ - -import cpp -import CastSanity diff --git a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll index 277d0e7b517..59447d983e2 100644 --- a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll +++ b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll @@ -1,3 +1,8 @@ +/** + * Provides a class and predicate for recognizing files that are likely to have been generated + * automatically. + */ + import semmle.code.cpp.Comments import semmle.code.cpp.File import semmle.code.cpp.Preprocessor diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 5aa9f43f48b..f81f00064d7 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C++ classes, including structs, unions, and template classes. + */ + import semmle.code.cpp.Type import semmle.code.cpp.UserType import semmle.code.cpp.metrics.MetricClass @@ -29,7 +33,7 @@ private import semmle.code.cpp.internal.ResolveClass class Class extends UserType { Class() { isClass(underlyingElement(this)) } - override string getCanonicalQLClass() { result = "Class" } + override string getAPrimaryQlClass() { result = "Class" } /** Gets a child declaration of this class, struct or union. */ override Declaration getADeclaration() { result = this.getAMember() } @@ -764,7 +768,7 @@ class ClassDerivation extends Locatable, @derivation { */ Class getBaseClass() { result = getBaseType().getUnderlyingType() } - override string getCanonicalQLClass() { result = "ClassDerivation" } + override string getAPrimaryQlClass() { result = "ClassDerivation" } /** * Gets the type from which we are deriving, without resolving any @@ -845,9 +849,7 @@ class ClassDerivation extends Locatable, @derivation { class LocalClass extends Class { LocalClass() { isLocal() } - override string getCanonicalQLClass() { - not this instanceof LocalStruct and result = "LocalClass" - } + override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" } override Function getEnclosingAccessHolder() { result = this.getEnclosingFunction() } } @@ -868,7 +870,7 @@ class LocalClass extends Class { class NestedClass extends Class { NestedClass() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedStruct and result = "NestedClass" } @@ -889,7 +891,7 @@ class NestedClass extends Class { class AbstractClass extends Class { AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) } - override string getCanonicalQLClass() { result = "AbstractClass" } + override string getAPrimaryQlClass() { result = "AbstractClass" } } /** @@ -930,7 +932,7 @@ class TemplateClass extends Class { exists(result.getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateClass" } + override string getAPrimaryQlClass() { result = "TemplateClass" } } /** @@ -951,7 +953,7 @@ class ClassTemplateInstantiation extends Class { ClassTemplateInstantiation() { tc.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "ClassTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "ClassTemplateInstantiation" } /** * Gets the class template from which this instantiation was instantiated. @@ -992,7 +994,7 @@ abstract class ClassTemplateSpecialization extends Class { count(int i | exists(result.getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "ClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "ClassTemplateSpecialization" } } /** @@ -1021,7 +1023,7 @@ class FullClassTemplateSpecialization extends ClassTemplateSpecialization { not this instanceof ClassTemplateInstantiation } - override string getCanonicalQLClass() { result = "FullClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FullClassTemplateSpecialization" } } /** @@ -1060,7 +1062,7 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization { count(int i | exists(getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "PartialClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" } } /** @@ -1085,7 +1087,7 @@ deprecated class Interface extends Class { ) } - override string getCanonicalQLClass() { result = "Interface" } + override string getAPrimaryQlClass() { result = "Interface" } } /** @@ -1100,7 +1102,7 @@ deprecated class Interface extends Class { class VirtualClassDerivation extends ClassDerivation { VirtualClassDerivation() { hasSpecifier("virtual") } - override string getCanonicalQLClass() { result = "VirtualClassDerivation" } + override string getAPrimaryQlClass() { result = "VirtualClassDerivation" } } /** @@ -1120,7 +1122,7 @@ class VirtualClassDerivation extends ClassDerivation { class VirtualBaseClass extends Class { VirtualBaseClass() { exists(VirtualClassDerivation cd | cd.getBaseClass() = this) } - override string getCanonicalQLClass() { result = "VirtualBaseClass" } + override string getAPrimaryQlClass() { result = "VirtualBaseClass" } /** A virtual class derivation of which this class/struct is the base. */ VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this } @@ -1142,7 +1144,7 @@ class VirtualBaseClass extends Class { class ProxyClass extends UserType { ProxyClass() { usertypes(underlyingElement(this), _, 9) } - override string getCanonicalQLClass() { result = "ProxyClass" } + override string getAPrimaryQlClass() { result = "ProxyClass" } /** Gets the location of the proxy class. */ override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll index 7f961bfd6f6..65e2af5fd22 100644 --- a/cpp/ql/src/semmle/code/cpp/Comments.qll +++ b/cpp/ql/src/semmle/code/cpp/Comments.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C and C++ comments. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Element diff --git a/cpp/ql/src/semmle/code/cpp/Compilation.qll b/cpp/ql/src/semmle/code/cpp/Compilation.qll index 691c0e08de3..812c417dbdd 100644 --- a/cpp/ql/src/semmle/code/cpp/Compilation.qll +++ b/cpp/ql/src/semmle/code/cpp/Compilation.qll @@ -1,3 +1,7 @@ +/** + * Provides a class representing individual compiler invocations that occurred during the build. + */ + import semmle.code.cpp.File /* diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 840705b01b5..e5d3d83326b 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with C and C++ declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Specifier import semmle.code.cpp.Namespace @@ -98,7 +102,12 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName(namespaceQualifier, "", baseName) } - override string toString() { result = this.getName() } + /** + * Gets a description of this `Declaration` for display purposes. + */ + string getDescription() { result = this.getName() } + + final override string toString() { result = this.getDescription() } /** * Gets the name of this declaration. @@ -115,7 +124,7 @@ class Declaration extends Locatable, @declaration { * To test whether this declaration has a particular name in the global * namespace, use `hasGlobalName`. */ - abstract string getName(); + string getName() { none() } // overridden in subclasses /** Holds if this declaration has the given name. */ predicate hasName(string name) { name = this.getName() } @@ -131,7 +140,7 @@ class Declaration extends Locatable, @declaration { } /** Gets a specifier of this declaration. */ - abstract Specifier getASpecifier(); + Specifier getASpecifier() { none() } // overridden in subclasses /** Holds if this declaration has a specifier with the given name. */ predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) } @@ -147,7 +156,7 @@ class Declaration extends Locatable, @declaration { * Gets the location of a declaration entry corresponding to this * declaration. */ - abstract Location getADeclarationLocation(); + Location getADeclarationLocation() { none() } // overridden in subclasses /** * Gets the declaration entry corresponding to this declaration that is a @@ -156,7 +165,7 @@ class Declaration extends Locatable, @declaration { DeclarationEntry getDefinition() { none() } /** Gets the location of the definition, if any. */ - abstract Location getDefinitionLocation(); + Location getDefinitionLocation() { none() } // overridden in subclasses /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } @@ -280,6 +289,8 @@ class Declaration extends Locatable, @declaration { } } +private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl; + /** * A C/C++ declaration entry. For example the following code contains five * declaration entries: @@ -295,9 +306,9 @@ class Declaration extends Locatable, @declaration { * See the comment above `Declaration` for an explanation of the relationship * between `Declaration` and `DeclarationEntry`. */ -abstract class DeclarationEntry extends Locatable { +class DeclarationEntry extends Locatable, TDeclarationEntry { /** Gets a specifier associated with this declaration entry. */ - abstract string getASpecifier(); + string getASpecifier() { none() } // overridden in subclasses /** * Gets the name associated with the corresponding definition (where @@ -320,10 +331,10 @@ abstract class DeclarationEntry extends Locatable { * `I.getADeclarationEntry()` returns `D` * but `D.getDeclaration()` only returns `C` */ - abstract Declaration getDeclaration(); + Declaration getDeclaration() { none() } // overridden in subclasses /** Gets the name associated with this declaration entry, if any. */ - abstract string getName(); + string getName() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry. @@ -332,7 +343,7 @@ abstract class DeclarationEntry extends Locatable { * For function declarations, get the return type of the function. * For type declarations, get the type being declared. */ - abstract Type getType(); + Type getType() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry after specifiers @@ -350,7 +361,7 @@ abstract class DeclarationEntry extends Locatable { predicate hasSpecifier(string specifier) { getASpecifier() = specifier } /** Holds if this declaration entry is a definition. */ - abstract predicate isDefinition(); + predicate isDefinition() { none() } // overridden in subclasses override string toString() { if isDefinition() @@ -362,6 +373,8 @@ abstract class DeclarationEntry extends Locatable { } } +private class TAccessHolder = @function or @usertype; + /** * A declaration that can potentially have more C++ access rights than its * enclosing element. This comprises `Class` (they have access to their own @@ -383,7 +396,7 @@ abstract class DeclarationEntry extends Locatable { * the informal phrase "_R_ occurs in a member or friend of class C", where * `AccessHolder` corresponds to this _R_. */ -abstract class AccessHolder extends Declaration { +class AccessHolder extends Declaration, TAccessHolder { /** * Holds if `this` can access private members of class `c`. * @@ -401,7 +414,7 @@ abstract class AccessHolder extends Declaration { /** * Gets the nearest enclosing `AccessHolder`. */ - abstract AccessHolder getEnclosingAccessHolder(); + AccessHolder getEnclosingAccessHolder() { none() } // overridden in subclasses /** * Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140 diff --git a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll index 37459602c03..79074fa8657 100644 --- a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll +++ b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing warnings generated during compilation. + */ + import semmle.code.cpp.Location /** A compiler-generated error, warning or remark. */ diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 2b236147484..77a27d49725 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -1,3 +1,8 @@ +/** + * Provides the `Element` class, which is the base class for all classes representing C or C++ + * program elements. + */ + import semmle.code.cpp.Location private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -50,12 +55,21 @@ class ElementBase extends @element { cached string toString() { none() } + /** DEPRECATED: use `getAPrimaryQlClass` instead. */ + deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() } + /** - * Canonical QL class corresponding to this element. + * Gets the name of a primary CodeQL class to which this element belongs. * - * ElementBase is the root class for this predicate. + * For most elements, this is simply the most precise syntactic category to + * which they belong; for example, `AddExpr` is a primary class, but + * `BinaryOperation` is not. + * + * This predicate always has a result. If no primary class can be + * determined, the result is `"???"`. If multiple primary classes match, + * this predicate can have multiple results. */ - string getCanonicalQLClass() { result = "???" } + string getAPrimaryQlClass() { result = "???" } } /** @@ -261,8 +275,14 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) { class StaticAssert extends Locatable, @static_assert { override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" } + /** + * Gets the expression which this static assertion ensures is true. + */ Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) } + /** + * Gets the message which will be reported by the compiler if this static assertion fails. + */ string getMessage() { static_asserts(underlyingElement(this), _, result, _) } override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) } diff --git a/cpp/ql/src/semmle/code/cpp/Enclosing.qll b/cpp/ql/src/semmle/code/cpp/Enclosing.qll index 07d39b10e83..d821589a76c 100644 --- a/cpp/ql/src/semmle/code/cpp/Enclosing.qll +++ b/cpp/ql/src/semmle/code/cpp/Enclosing.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for finding the smallest element that encloses an expression or statement. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/Enum.qll b/cpp/ql/src/semmle/code/cpp/Enum.qll index e3a2ef60ccc..9cddeb78f9b 100644 --- a/cpp/ql/src/semmle/code/cpp/Enum.qll +++ b/cpp/ql/src/semmle/code/cpp/Enum.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C/C++ enums and enum constants. + */ + import semmle.code.cpp.Type private import semmle.code.cpp.internal.ResolveClass @@ -19,11 +23,22 @@ class Enum extends UserType, IntegralOrEnumType { /** Gets an enumerator of this enumeration. */ EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this } + /** + * Gets the enumerator of this enumeration that was declared at the zero-based position `index`. + * For example, `zero` is at index 2 in the following declaration: + * ``` + * enum ReversedOrder { + * two = 2, + * one = 1, + * zero = 0 + * }; + * ``` + */ EnumConstant getEnumConstant(int index) { enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _) } - override string getCanonicalQLClass() { result = "Enum" } + override string getAPrimaryQlClass() { result = "Enum" } /** * Gets a descriptive string for the enum. This method is only intended to @@ -72,7 +87,7 @@ class Enum extends UserType, IntegralOrEnumType { class LocalEnum extends Enum { LocalEnum() { isLocal() } - override string getCanonicalQLClass() { result = "LocalEnum" } + override string getAPrimaryQlClass() { result = "LocalEnum" } } /** @@ -90,7 +105,7 @@ class LocalEnum extends Enum { class NestedEnum extends Enum { NestedEnum() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedEnum" } + override string getAPrimaryQlClass() { result = "NestedEnum" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } @@ -115,7 +130,7 @@ class NestedEnum extends Enum { class ScopedEnum extends Enum { ScopedEnum() { usertypes(underlyingElement(this), _, 13) } - override string getCanonicalQLClass() { result = "ScopedEnum" } + override string getAPrimaryQlClass() { result = "ScopedEnum" } } /** @@ -138,7 +153,7 @@ class EnumConstant extends Declaration, @enumconstant { enumconstants(underlyingElement(this), unresolveElement(result), _, _, _, _) } - override string getCanonicalQLClass() { result = "EnumConstant" } + override string getAPrimaryQlClass() { result = "EnumConstant" } override Class getDeclaringType() { result = this.getDeclaringEnum().getDeclaringType() } diff --git a/cpp/ql/src/semmle/code/cpp/Field.qll b/cpp/ql/src/semmle/code/cpp/Field.qll index eb864a16063..5ed5e8e4b4b 100644 --- a/cpp/ql/src/semmle/code/cpp/Field.qll +++ b/cpp/ql/src/semmle/code/cpp/Field.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C structure members and C++ non-static member variables. + */ + import semmle.code.cpp.Variable import semmle.code.cpp.Enum import semmle.code.cpp.exprs.Access @@ -19,7 +23,7 @@ import semmle.code.cpp.exprs.Access class Field extends MemberVariable { Field() { fieldoffsets(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "Field" } + override string getAPrimaryQlClass() { result = "Field" } /** * Gets the offset of this field in bytes from the start of its declaring @@ -86,7 +90,7 @@ class Field extends MemberVariable { class BitField extends Field { BitField() { bitfield(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "BitField" } + override string getAPrimaryQlClass() { result = "BitField" } /** * Gets the size of this bitfield in bits (on the machine where facts diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 60ef2d587ef..1887f43b70c 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -1,9 +1,13 @@ +/** + * Provides classes representing files and folders. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Declaration import semmle.code.cpp.metrics.MetricFile /** A file or folder. */ -abstract class Container extends Locatable, @container { +class Container extends Locatable, @container { /** * Gets the absolute, canonical path of this container, using forward slashes * as path separator. @@ -28,7 +32,7 @@ abstract class Container extends Locatable, @container { * a bare root prefix, that is, the path has no path segments. A container * whose absolute path has no segments is always a `Folder`, not a `File`. */ - abstract string getAbsolutePath(); + string getAbsolutePath() { none() } // overridden by subclasses /** * DEPRECATED: Use `getLocation` instead. @@ -36,7 +40,7 @@ abstract class Container extends Locatable, @container { * * For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls). */ - abstract deprecated string getURL(); + deprecated string getURL() { none() } // overridden by subclasses /** * Gets the relative path of this file or folder from the root folder of the @@ -174,7 +178,7 @@ class Folder extends Container, @folder { result.hasLocationInfo(_, 0, 0, 0, 0) } - override string getCanonicalQLClass() { result = "Folder" } + override string getAPrimaryQlClass() { result = "Folder" } /** * DEPRECATED: Use `getLocation` instead. @@ -242,7 +246,7 @@ class File extends Container, @file { override string toString() { result = Container.super.toString() } - override string getCanonicalQLClass() { result = "File" } + override string getAPrimaryQlClass() { result = "File" } override Location getLocation() { result.getContainer() = this and @@ -261,18 +265,6 @@ class File extends Container, @file { /** Holds if this file was compiled as C++ (at any point). */ predicate compiledAsCpp() { fileannotations(underlyingElement(this), 1, "compiled as c++", "1") } - /** - * DEPRECATED: Objective-C is no longer supported. - * Holds if this file was compiled as Objective C (at any point). - */ - deprecated predicate compiledAsObjC() { none() } - - /** - * DEPRECATED: Objective-C is no longer supported. - * Holds if this file was compiled as Objective C++ (at any point). - */ - deprecated predicate compiledAsObjCpp() { none() } - /** * Holds if this file was compiled by a Microsoft compiler (at any point). * @@ -316,14 +308,6 @@ class File extends Container, @file { exists(Include i | i.getFile() = this and i.getIncludedFile() = result) } - /** - * DEPRECATED: use `getParentContainer` instead. - * Gets the folder which contains this file. - */ - deprecated Folder getParent() { - containerparent(unresolveElement(result), underlyingElement(this)) - } - /** * Holds if this file may be from source. This predicate holds for all files * except the dummy file, whose name is the empty string, which contains @@ -341,28 +325,6 @@ class File extends Container, @file { /** Gets the metric file. */ MetricFile getMetrics() { result = this } - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Gets the full name of this file, for example: - * "/usr/home/me/myprogram.c". - */ - deprecated string getName() { files(underlyingElement(this), result, _, _, _) } - - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Holds if this file has the specified full name. - * - * Example usage: `f.hasName("/usr/home/me/myprogram.c")`. - */ - deprecated predicate hasName(string name) { name = this.getName() } - - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Gets the full name of this file, for example - * "/usr/home/me/myprogram.c". - */ - deprecated string getFullName() { result = this.getName() } - /** * Gets the remainder of the base name after the first dot character. Note * that the name of this predicate is in plural form, unlike `getExtension`, @@ -377,22 +339,6 @@ class File extends Container, @file { */ string getExtensions() { files(underlyingElement(this), _, _, result, _) } - /** - * DEPRECATED: Use `getBaseName` instead. - * Gets the name and extension(s), but not path, of a file. For example, - * if the full name is "/path/to/filename.a.bcd" then the filename is - * "filename.a.bcd". - */ - deprecated string getFileName() { - // [a/b.c/d/]fileName - // ^ beginAfter - exists(string fullName, int beginAfter | - fullName = this.getName() and - beginAfter = max(int i | i = -1 or fullName.charAt(i) = "/" | i) and - result = fullName.suffix(beginAfter + 1) - ) - } - /** * Gets the short name of this file, that is, the prefix of its base name up * to (but not including) the first dot character if there is one, or the @@ -436,7 +382,7 @@ class HeaderFile extends File { exists(Include i | i.getIncludedFile() = this) } - override string getCanonicalQLClass() { result = "HeaderFile" } + override string getAPrimaryQlClass() { result = "HeaderFile" } /** * Holds if this header file does not contain any declaration entries or top level @@ -462,7 +408,7 @@ class HeaderFile extends File { class CFile extends File { CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") } - override string getCanonicalQLClass() { result = "CFile" } + override string getAPrimaryQlClass() { result = "CFile" } } /** @@ -490,7 +436,7 @@ class CppFile extends File { ) } - override string getCanonicalQLClass() { result = "CppFile" } + override string getAPrimaryQlClass() { result = "CppFile" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll index c788ea70058..9a35f7527d5 100644 --- a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll +++ b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll @@ -1,3 +1,7 @@ +/** + * Provides a class representing C++ `friend` declarations. + */ + import semmle.code.cpp.Declaration private import semmle.code.cpp.internal.ResolveClass @@ -23,7 +27,7 @@ class FriendDecl extends Declaration, @frienddecl { */ override Location getADeclarationLocation() { result = this.getLocation() } - override string getCanonicalQLClass() { result = "FriendDecl" } + override string getAPrimaryQlClass() { result = "FriendDecl" } /** * Implements the abstract method `Declaration.getDefinitionLocation`. A diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 90998ed4ea3..0a63da4a174 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -1,5 +1,8 @@ +/** + * Provides classes for working with functions, including template functions. + */ + import semmle.code.cpp.Location -import semmle.code.cpp.Member import semmle.code.cpp.Class import semmle.code.cpp.Parameter import semmle.code.cpp.exprs.Call @@ -184,17 +187,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * For example: for a function `int Foo(int p1, int p2)` this would * return `int p1, int p2`. */ - string getParameterString() { result = getParameterStringFrom(0) } - - private string getParameterStringFrom(int index) { - index = getNumberOfParameters() and - result = "" - or - index = getNumberOfParameters() - 1 and - result = getParameter(index).getTypedName() - or - index < getNumberOfParameters() - 1 and - result = getParameter(index).getTypedName() + ", " + getParameterStringFrom(index + 1) + string getParameterString() { + result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i) } /** Gets a call to this function. */ @@ -519,7 +513,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** Gets the function which is being declared or defined. */ override Function getDeclaration() { result = getFunction() } - override string getCanonicalQLClass() { result = "FunctionDeclarationEntry" } + override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" } /** Gets the function which is being declared or defined. */ Function getFunction() { fun_decls(underlyingElement(this), unresolveElement(result), _, _, _) } @@ -616,18 +610,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * For example: for a function 'int Foo(int p1, int p2)' this would * return 'int p1, int p2'. */ - string getParameterString() { result = getParameterStringFrom(0) } - - private string getParameterStringFrom(int index) { - index = getNumberOfParameters() and - result = "" - or - index = getNumberOfParameters() - 1 and - result = getParameterDeclarationEntry(index).getTypedName() - or - index < getNumberOfParameters() - 1 and - result = - getParameterDeclarationEntry(index).getTypedName() + ", " + getParameterStringFrom(index + 1) + string getParameterString() { + result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i) } /** @@ -714,428 +698,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { class TopLevelFunction extends Function { TopLevelFunction() { not this.isMember() } - override string getCanonicalQLClass() { result = "TopLevelFunction" } -} - -/** - * A C++ function declared as a member of a class [N4140 9.3]. This includes - * static member functions. For example the functions `MyStaticMemberFunction` - * and `MyMemberFunction` in: - * ``` - * class MyClass { - * public: - * void MyMemberFunction() { - * DoSomething(); - * } - * - * static void MyStaticMemberFunction() { - * DoSomething(); - * } - * }; - * ``` - */ -class MemberFunction extends Function { - MemberFunction() { this.isMember() } - - override string getCanonicalQLClass() { - not this instanceof CopyAssignmentOperator and - not this instanceof MoveAssignmentOperator and - result = "MemberFunction" - } - - /** - * Gets the number of parameters of this function, including any implicit - * `this` parameter. - */ - override int getEffectiveNumberOfParameters() { - if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 - } - - /** Holds if this member is private. */ - predicate isPrivate() { this.hasSpecifier("private") } - - /** Holds if this member is protected. */ - predicate isProtected() { this.hasSpecifier("protected") } - - /** Holds if this member is public. */ - predicate isPublic() { this.hasSpecifier("public") } - - /** Holds if this function overrides that function. */ - predicate overrides(MemberFunction that) { - overrides(underlyingElement(this), unresolveElement(that)) - } - - /** Gets a directly overridden function. */ - MemberFunction getAnOverriddenFunction() { this.overrides(result) } - - /** Gets a directly overriding function. */ - MemberFunction getAnOverridingFunction() { result.overrides(this) } - - /** - * Gets the declaration entry for this member function that is within the - * class body. - */ - FunctionDeclarationEntry getClassBodyDeclarationEntry() { - if strictcount(getADeclarationEntry()) = 1 - then result = getDefinition() - else ( - result = getADeclarationEntry() and result != getDefinition() - ) - } -} - -/** - * A C++ virtual function. For example the two functions called - * `myVirtualFunction` in the following code are each a - * `VirtualFunction`: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class VirtualFunction extends MemberFunction { - VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "VirtualFunction" } - - /** Holds if this virtual function is pure. */ - predicate isPure() { this instanceof PureVirtualFunction } - - /** - * Holds if this function was declared with the `override` specifier - * [N4140 10.3]. - */ - predicate isOverrideExplicit() { this.hasSpecifier("override") } -} - -/** - * A C++ pure virtual function [N4140 10.4]. For example the first function - * called `myVirtualFunction` in the following code: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class PureVirtualFunction extends VirtualFunction { - PureVirtualFunction() { purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "PureVirtualFunction" } -} - -/** - * A const C++ member function [N4140 9.3.1/4]. A const function has the - * `const` specifier and does not modify the state of its class. For example - * the member function `day` in the following code: - * ``` - * class MyClass { - * ... - * - * int day() const { - * return d; - * } - * - * ... - * }; - * ``` - */ -class ConstMemberFunction extends MemberFunction { - ConstMemberFunction() { this.hasSpecifier("const") } - - override string getCanonicalQLClass() { result = "ConstMemberFunction" } -} - -/** - * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the - * following code is a constructor: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class Constructor extends MemberFunction { - Constructor() { functions(underlyingElement(this), _, 2) } - - override string getCanonicalQLClass() { result = "Constructor" } - - /** - * Holds if this constructor serves as a default constructor. - * - * This holds for constructors with zero formal parameters. It also holds - * for constructors which have a non-zero number of formal parameters, - * provided that every parameter has a default value. - */ - predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. - */ - ConstructorInit getAnInitializer() { result = getInitializer(_) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. The index specifies the order in which the initializer is - * to be evaluated. - */ - ConstructorInit getInitializer(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A function that defines an implicit conversion. - */ -abstract class ImplicitConversionFunction extends MemberFunction { - abstract Type getSourceType(); - - abstract Type getDestType(); -} - -/** - * A C++ constructor that also defines an implicit conversion. For example the - * function `MyClass` in the following code is a `ConversionConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyOtherClass &from) { - * ... - * } - * }; - * ``` - */ -class ConversionConstructor extends Constructor, ImplicitConversionFunction { - ConversionConstructor() { - strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and - not hasSpecifier("explicit") and - not this instanceof CopyConstructor - } - - override string getCanonicalQLClass() { - not this instanceof MoveConstructor and result = "ConversionConstructor" - } - - /** Gets the type this `ConversionConstructor` takes as input. */ - override Type getSourceType() { result = this.getParameter(0).getType() } - - /** Gets the type this `ConversionConstructor` is a constructor of. */ - override Type getDestType() { result = this.getDeclaringType() } -} - -private predicate hasCopySignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() -} - -private predicate hasMoveSignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() -} - -/** - * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `CopyConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyClass &from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a copy constructor of class `T` is a non-template - * constructor whose first parameter has type `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`, and either there are no other parameters, - * or the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a copy constructor. For such classes, `CopyConstructor` - * over-approximates the set of copy constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeCopyConstructorInInstantiation`. - */ -class CopyConstructor extends Constructor { - CopyConstructor() { - hasCopySignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a copy - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a copy - * constructor. - */ - predicate mayNotBeCopyConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `MoveConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(MyClass &&from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a move constructor of class `T` is a non-template - * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`, and either there are no other parameters, or - * the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a move constructor. For such classes, `MoveConstructor` - * over-approximates the set of move constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeMoveConstructorInInstantiation`. - */ -class MoveConstructor extends Constructor { - MoveConstructor() { - hasMoveSignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a move - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a move - * constructor. - */ - predicate mayNotBeMoveConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ constructor that takes no arguments ('default' constructor). This - * is the constructor that is invoked when no initializer is given. For - * example the function `MyClass` in the following code is a - * `NoArgConstructor`: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class NoArgConstructor extends Constructor { - NoArgConstructor() { this.getNumberOfParameters() = 0 } -} - -/** - * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the - * following code is a destructor: - * ``` - * class MyClass { - * public: - * ~MyClass() { - * ... - * } - * }; - * ``` - */ -class Destructor extends MemberFunction { - Destructor() { functions(underlyingElement(this), _, 3) } - - override string getCanonicalQLClass() { result = "Destructor" } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. - */ - DestructorDestruction getADestruction() { result = getDestruction(_) } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. The index specifies the order in which the destruction should - * be evaluated. - */ - DestructorDestruction getDestruction(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A C++ conversion operator [N4140 12.3.2]. For example the function - * `operator int` in the following code is a `ConversionOperator`: - * ``` - * class MyClass { - * public: - * operator int(); - * }; - * ``` - */ -class ConversionOperator extends MemberFunction, ImplicitConversionFunction { - ConversionOperator() { functions(underlyingElement(this), _, 4) } - - override string getCanonicalQLClass() { result = "ConversionOperator" } - - override Type getSourceType() { result = this.getDeclaringType() } - - override Type getDestType() { result = this.getType() } + override string getAPrimaryQlClass() { result = "TopLevelFunction" } } /** @@ -1144,69 +707,11 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { class Operator extends Function { Operator() { functions(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof MemberFunction and result = "Operator" } } -/** - * A C++ copy assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `CopyAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(const MyClass &other); - * }; - * ``` - * - * As per the standard, a copy assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`. - */ -class CopyAssignmentOperator extends Operator { - CopyAssignmentOperator() { - hasName("operator=") and - ( - hasCopySignature(this) - or - // Unlike CopyConstructor, this member allows a non-reference - // parameter. - getParameter(0).getUnspecifiedType() = getDeclaringType() - ) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } -} - -/** - * A C++ move assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `MoveAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(MyClass &&other); - * }; - * ``` - * - * As per the standard, a move assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`. - */ -class MoveAssignmentOperator extends Operator { - MoveAssignmentOperator() { - hasName("operator=") and - hasMoveSignature(this) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } -} - /** * A C++ function which has a non-empty template argument list. For example * the function `myTemplateFunction` in the following code: @@ -1233,7 +738,7 @@ class TemplateFunction extends Function { is_function_template(underlyingElement(this)) and exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateFunction" } + override string getAPrimaryQlClass() { result = "TemplateFunction" } /** * Gets a compiler-generated instantiation of this function template. @@ -1273,7 +778,7 @@ class FunctionTemplateInstantiation extends Function { FunctionTemplateInstantiation() { tf.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "FunctionTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "FunctionTemplateInstantiation" } /** * Gets the function template from which this instantiation was instantiated. @@ -1318,7 +823,7 @@ class FunctionTemplateInstantiation extends Function { class FunctionTemplateSpecialization extends Function { FunctionTemplateSpecialization() { this.isSpecialization() } - override string getCanonicalQLClass() { result = "FunctionTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FunctionTemplateSpecialization" } /** * Gets the primary template for the specialization (the function template diff --git a/cpp/ql/src/semmle/code/cpp/Include.qll b/cpp/ql/src/semmle/code/cpp/Include.qll index f5e4fae619c..11702ce1bf6 100644 --- a/cpp/ql/src/semmle/code/cpp/Include.qll +++ b/cpp/ql/src/semmle/code/cpp/Include.qll @@ -1,3 +1,8 @@ +/** + * Provides classes representing C/C++ `#include`, `#include_next`, and `#import` preprocessor + * directives. + */ + import semmle.code.cpp.Preprocessor /** diff --git a/cpp/ql/src/semmle/code/cpp/Initializer.qll b/cpp/ql/src/semmle/code/cpp/Initializer.qll index 80601f659da..643a880ddf2 100644 --- a/cpp/ql/src/semmle/code/cpp/Initializer.qll +++ b/cpp/ql/src/semmle/code/cpp/Initializer.qll @@ -1,3 +1,7 @@ +/** + * Provides the `Initializer` class, representing C/C++ declaration initializers. + */ + import semmle.code.cpp.controlflow.ControlFlowGraph /** @@ -18,7 +22,7 @@ import semmle.code.cpp.controlflow.ControlFlowGraph class Initializer extends ControlFlowNode, @initialiser { override Location getLocation() { initialisers(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "Initializer" } + override string getAPrimaryQlClass() { result = "Initializer" } /** Holds if this initializer is explicit in the source. */ override predicate fromSource() { not this.getLocation() instanceof UnknownLocation } diff --git a/cpp/ql/src/semmle/code/cpp/Iteration.qll b/cpp/ql/src/semmle/code/cpp/Iteration.qll index fd7ba60ea19..d87306c4bab 100644 --- a/cpp/ql/src/semmle/code/cpp/Iteration.qll +++ b/cpp/ql/src/semmle/code/cpp/Iteration.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for loop iteration variables. + */ + import semmle.code.cpp.Variable /** @@ -7,14 +11,18 @@ import semmle.code.cpp.Variable class LoopCounter extends Variable { LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its counter. + /** + * Gets a loop which uses this variable as its counter. + */ ForStmt getALoop() { result.getAnIterationVariable() = this } } @@ -25,14 +33,18 @@ class LoopCounter extends Variable { class LoopControlVariable extends Variable { LoopControlVariable() { this = loopControlVariable(_) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its control variable. + /** + * Gets a loop which uses this variable as its control variable. + */ ForStmt getALoop() { this = loopControlVariable(result) } } diff --git a/cpp/ql/src/semmle/code/cpp/Linkage.qll b/cpp/ql/src/semmle/code/cpp/Linkage.qll index 7912c9e25e1..54a6099eaef 100644 --- a/cpp/ql/src/semmle/code/cpp/Linkage.qll +++ b/cpp/ql/src/semmle/code/cpp/Linkage.qll @@ -1,3 +1,7 @@ +/** + * Proivdes the `LinkTarget` class representing linker invocations during the build process. + */ + import semmle.code.cpp.Class import semmle.code.cpp.File import semmle.code.cpp.Function diff --git a/cpp/ql/src/semmle/code/cpp/Location.qll b/cpp/ql/src/semmle/code/cpp/Location.qll index 129ffba0f74..74bf0872be2 100644 --- a/cpp/ql/src/semmle/code/cpp/Location.qll +++ b/cpp/ql/src/semmle/code/cpp/Location.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for locations in the source code. + */ + import semmle.code.cpp.Element import semmle.code.cpp.File @@ -11,16 +15,16 @@ class Location extends @location { /** Gets the file corresponding to this location, if any. */ File getFile() { result = this.getContainer() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { this.fullLocationInfo(_, result, _, _, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { this.fullLocationInfo(_, _, result, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { this.fullLocationInfo(_, _, _, result, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { this.fullLocationInfo(_, _, _, _, result) } /** diff --git a/cpp/ql/src/semmle/code/cpp/Macro.qll b/cpp/ql/src/semmle/code/cpp/Macro.qll index 389634912b7..aa4b8d41999 100644 --- a/cpp/ql/src/semmle/code/cpp/Macro.qll +++ b/cpp/ql/src/semmle/code/cpp/Macro.qll @@ -13,7 +13,7 @@ class Macro extends PreprocessorDirective, @ppd_define { */ override string getHead() { preproctext(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "Macro" } + override string getAPrimaryQlClass() { result = "Macro" } /** * Gets the body of this macro. For example, `(((x)>(y))?(x):(y))` in @@ -74,7 +74,7 @@ class MacroAccess extends Locatable, @macroinvocation { */ override Location getLocation() { result = this.getOutermostMacroAccess().getActualLocation() } - override string getCanonicalQLClass() { result = "MacroAccess" } + override string getAPrimaryQlClass() { result = "MacroAccess" } /** * Gets the location of this macro access. For a nested access, where @@ -147,7 +147,7 @@ class MacroAccess extends Locatable, @macroinvocation { class MacroInvocation extends MacroAccess { MacroInvocation() { macroinvocations(underlyingElement(this), _, _, 1) } - override string getCanonicalQLClass() { result = "MacroInvocation" } + override string getAPrimaryQlClass() { result = "MacroInvocation" } /** * Gets an element that occurs in this macro invocation or a nested macro @@ -179,6 +179,11 @@ class MacroInvocation extends MacroAccess { result.(Stmt).getGeneratingMacro() = this } + /** + * Gets a function that includes an expression that is affected by this macro + * invocation. If the macro expansion includes the end of one function and + * the beginning of another, this predicate will get both. + */ Function getEnclosingFunction() { result = this.getAnAffectedElement().(Expr).getEnclosingFunction() } diff --git a/cpp/ql/src/semmle/code/cpp/Member.qll b/cpp/ql/src/semmle/code/cpp/Member.qll index 92769486ae9..f47edbddeba 100644 --- a/cpp/ql/src/semmle/code/cpp/Member.qll +++ b/cpp/ql/src/semmle/code/cpp/Member.qll @@ -1,2 +1,6 @@ +/** + * DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll new file mode 100644 index 00000000000..151fb6618af --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -0,0 +1,495 @@ +/** + * Provides classes for working with C++ member functions, constructors, destructors, + * and user-defined operators. + */ + +import cpp + +/** + * A C++ function declared as a member of a class [N4140 9.3]. This includes + * static member functions. For example the functions `MyStaticMemberFunction` + * and `MyMemberFunction` in: + * ``` + * class MyClass { + * public: + * void MyMemberFunction() { + * DoSomething(); + * } + * + * static void MyStaticMemberFunction() { + * DoSomething(); + * } + * }; + * ``` + */ +class MemberFunction extends Function { + MemberFunction() { this.isMember() } + + override string getAPrimaryQlClass() { + not this instanceof CopyAssignmentOperator and + not this instanceof MoveAssignmentOperator and + result = "MemberFunction" + } + + /** + * Gets the number of parameters of this function, including any implicit + * `this` parameter. + */ + override int getEffectiveNumberOfParameters() { + if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 + } + + /** Holds if this member is private. */ + predicate isPrivate() { this.hasSpecifier("private") } + + /** Holds if this member is protected. */ + predicate isProtected() { this.hasSpecifier("protected") } + + /** Holds if this member is public. */ + predicate isPublic() { this.hasSpecifier("public") } + + /** Holds if this function overrides that function. */ + predicate overrides(MemberFunction that) { + overrides(underlyingElement(this), unresolveElement(that)) + } + + /** Gets a directly overridden function. */ + MemberFunction getAnOverriddenFunction() { this.overrides(result) } + + /** Gets a directly overriding function. */ + MemberFunction getAnOverridingFunction() { result.overrides(this) } + + /** + * Gets the declaration entry for this member function that is within the + * class body. + */ + FunctionDeclarationEntry getClassBodyDeclarationEntry() { + if strictcount(getADeclarationEntry()) = 1 + then result = getDefinition() + else ( + result = getADeclarationEntry() and result != getDefinition() + ) + } + + /** + * Gets the type of the `this` parameter associated with this member function, if any. The type + * may have `const` and/or `volatile` qualifiers, matching the function declaration. + */ + PointerType getTypeOfThis() { + member_function_this_type(underlyingElement(this), unresolveElement(result)) + } +} + +/** + * A C++ virtual function. For example the two functions called + * `myVirtualFunction` in the following code are each a + * `VirtualFunction`: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class VirtualFunction extends MemberFunction { + VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } + + override string getAPrimaryQlClass() { result = "VirtualFunction" } + + /** Holds if this virtual function is pure. */ + predicate isPure() { this instanceof PureVirtualFunction } + + /** + * Holds if this function was declared with the `override` specifier + * [N4140 10.3]. + */ + predicate isOverrideExplicit() { this.hasSpecifier("override") } +} + +/** + * A C++ pure virtual function [N4140 10.4]. For example the first function + * called `myVirtualFunction` in the following code: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class PureVirtualFunction extends VirtualFunction { + PureVirtualFunction() { purefunctions(underlyingElement(this)) } + + override string getAPrimaryQlClass() { result = "PureVirtualFunction" } +} + +/** + * A const C++ member function [N4140 9.3.1/4]. A const function has the + * `const` specifier and does not modify the state of its class. For example + * the member function `day` in the following code: + * ``` + * class MyClass { + * ... + * + * int day() const { + * return d; + * } + * + * ... + * }; + * ``` + */ +class ConstMemberFunction extends MemberFunction { + ConstMemberFunction() { this.hasSpecifier("const") } + + override string getAPrimaryQlClass() { result = "ConstMemberFunction" } +} + +/** + * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the + * following code is a constructor: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class Constructor extends MemberFunction { + Constructor() { functions(underlyingElement(this), _, 2) } + + override string getAPrimaryQlClass() { result = "Constructor" } + + /** + * Holds if this constructor serves as a default constructor. + * + * This holds for constructors with zero formal parameters. It also holds + * for constructors which have a non-zero number of formal parameters, + * provided that every parameter has a default value. + */ + predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. + */ + ConstructorInit getAnInitializer() { result = getInitializer(_) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. The index specifies the order in which the initializer is + * to be evaluated. + */ + ConstructorInit getInitializer(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A function that defines an implicit conversion. + */ +abstract class ImplicitConversionFunction extends MemberFunction { + /** Gets the type this `ImplicitConversionFunction` takes as input. */ + abstract Type getSourceType(); + + /** Gets the type this `ImplicitConversionFunction` converts to. */ + abstract Type getDestType(); +} + +/** + * A C++ constructor that also defines an implicit conversion. For example the + * function `MyClass` in the following code is a `ConversionConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyOtherClass &from) { + * ... + * } + * }; + * ``` + */ +class ConversionConstructor extends Constructor, ImplicitConversionFunction { + ConversionConstructor() { + strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and + not hasSpecifier("explicit") and + not this instanceof CopyConstructor + } + + override string getAPrimaryQlClass() { + not this instanceof MoveConstructor and result = "ConversionConstructor" + } + + /** Gets the type this `ConversionConstructor` takes as input. */ + override Type getSourceType() { result = this.getParameter(0).getType() } + + /** Gets the type this `ConversionConstructor` is a constructor of. */ + override Type getDestType() { result = this.getDeclaringType() } +} + +private predicate hasCopySignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() +} + +private predicate hasMoveSignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() +} + +/** + * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `CopyConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyClass &from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a copy constructor of class `T` is a non-template + * constructor whose first parameter has type `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`, and either there are no other parameters, + * or the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a copy constructor. For such classes, `CopyConstructor` + * over-approximates the set of copy constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeCopyConstructorInInstantiation`. + */ +class CopyConstructor extends Constructor { + CopyConstructor() { + hasCopySignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "CopyConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a copy + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a copy + * constructor. + */ + predicate mayNotBeCopyConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `MoveConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(MyClass &&from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a move constructor of class `T` is a non-template + * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`, and either there are no other parameters, or + * the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a move constructor. For such classes, `MoveConstructor` + * over-approximates the set of move constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeMoveConstructorInInstantiation`. + */ +class MoveConstructor extends Constructor { + MoveConstructor() { + hasMoveSignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "MoveConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a move + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a move + * constructor. + */ + predicate mayNotBeMoveConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ constructor that takes no arguments ('default' constructor). This + * is the constructor that is invoked when no initializer is given. For + * example the function `MyClass` in the following code is a + * `NoArgConstructor`: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class NoArgConstructor extends Constructor { + NoArgConstructor() { this.getNumberOfParameters() = 0 } +} + +/** + * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the + * following code is a destructor: + * ``` + * class MyClass { + * public: + * ~MyClass() { + * ... + * } + * }; + * ``` + */ +class Destructor extends MemberFunction { + Destructor() { functions(underlyingElement(this), _, 3) } + + override string getAPrimaryQlClass() { result = "Destructor" } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. + */ + DestructorDestruction getADestruction() { result = getDestruction(_) } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. The index specifies the order in which the destruction should + * be evaluated. + */ + DestructorDestruction getDestruction(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A C++ conversion operator [N4140 12.3.2]. For example the function + * `operator int` in the following code is a `ConversionOperator`: + * ``` + * class MyClass { + * public: + * operator int(); + * }; + * ``` + */ +class ConversionOperator extends MemberFunction, ImplicitConversionFunction { + ConversionOperator() { functions(underlyingElement(this), _, 4) } + + override string getAPrimaryQlClass() { result = "ConversionOperator" } + + override Type getSourceType() { result = this.getDeclaringType() } + + override Type getDestType() { result = this.getType() } +} + +/** + * A C++ copy assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `CopyAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(const MyClass &other); + * }; + * ``` + * + * As per the standard, a copy assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`. + */ +class CopyAssignmentOperator extends Operator { + CopyAssignmentOperator() { + hasName("operator=") and + ( + hasCopySignature(this) + or + // Unlike CopyConstructor, this member allows a non-reference + // parameter. + getParameter(0).getUnspecifiedType() = getDeclaringType() + ) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" } +} + +/** + * A C++ move assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `MoveAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(MyClass &&other); + * }; + * ``` + * + * As per the standard, a move assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`. + */ +class MoveAssignmentOperator extends Operator { + MoveAssignmentOperator() { + hasName("operator=") and + hasMoveSignature(this) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" } +} diff --git a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll index eff2c9205bf..042ee10700a 100644 --- a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll +++ b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for working with name qualifiers such as the `N::` in + * `N::f()`. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..6172c3af50c 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling namespaces, `using` directives and `using` declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type import semmle.code.cpp.metrics.MetricNamespace @@ -79,7 +83,10 @@ class Namespace extends NameQualifyingElement, @namespace { /** Gets the metric namespace. */ MetricNamespace getMetrics() { result = this } - override string toString() { result = this.getQualifiedName() } + /** Gets a version of the `QualifiedName` that is more suitable for display purposes. */ + string getFriendlyName() { result = this.getQualifiedName() } + + final override string toString() { result = getFriendlyName() } /** Gets a declaration of (part of) this namespace. */ NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this } @@ -104,7 +111,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { namespace_decls(underlyingElement(this), unresolveElement(result), _, _) } - override string toString() { result = this.getNamespace().toString() } + override string toString() { result = this.getNamespace().getFriendlyName() } /** * Gets the location of the token preceding the namespace declaration @@ -124,13 +131,13 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { */ Location getBodyLocation() { namespace_decls(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "NamespaceDeclarationEntry" } + override string getAPrimaryQlClass() { result = "NamespaceDeclarationEntry" } } /** * A C++ `using` directive or `using` declaration. */ -abstract class UsingEntry extends Locatable, @using { +class UsingEntry extends Locatable, @using { override Location getLocation() { usings(underlyingElement(this), _, result) } } @@ -150,7 +157,7 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using " + this.getDeclaration().toString() } + override string toString() { result = "using " + this.getDeclaration().getDescription() } } /** @@ -169,7 +176,7 @@ class UsingDirectiveEntry extends UsingEntry { */ Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using namespace " + this.getNamespace().toString() } + override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() } } /** @@ -204,7 +211,7 @@ class GlobalNamespace extends Namespace { */ deprecated string getFullName() { result = this.getName() } - override string toString() { result = "(global namespace)" } + override string getFriendlyName() { result = "(global namespace)" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/NestedFields.qll b/cpp/ql/src/semmle/code/cpp/NestedFields.qll index c4be8b8b9ff..ce67719a7e2 100644 --- a/cpp/ql/src/semmle/code/cpp/NestedFields.qll +++ b/cpp/ql/src/semmle/code/cpp/NestedFields.qll @@ -1,3 +1,8 @@ +/** + * Provides a class for reasoning about nested field accesses, for example + * the access `myLine.start.x`. + */ + import cpp /** @@ -25,7 +30,7 @@ private Expr getUltimateQualifier(FieldAccess fa) { } /** - * Accesses to nested fields. + * A nested field access, for example the access `myLine.start.x`. */ class NestedFieldAccess extends FieldAccess { Expr ultimateQualifier; @@ -35,6 +40,30 @@ class NestedFieldAccess extends FieldAccess { getTarget() = getANestedField(ultimateQualifier.getType().stripType()) } - /** Gets the ultimate qualifier of this nested field access. */ + /** + * Gets the outermost qualifier of this nested field access. In the + * following example, the access to `myLine.start.x` has outermost qualifier + * `myLine`: + * ``` + * struct Point + * { + * float x, y; + * }; + * + * struct Line + * { + * Point start, end; + * }; + * + * void init() + * { + * Line myLine; + * + * myLine.start.x = 0.0f; + * + * // ... + * } + * ``` + */ Expr getUltimateQualifier() { result = ultimateQualifier } } diff --git a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll index 5c99a47e674..d4b844c3bf7 100644 --- a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll @@ -1,3 +1,7 @@ +/** + * DEPRECATED: Objective-C is no longer supported. + */ + import semmle.code.cpp.Class private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 1fbd8b0f071..99ad822e072 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -1,3 +1,7 @@ +/** + * Provides a class that models parameters to functions. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Declaration private import semmle.code.cpp.internal.ResolveClass @@ -45,7 +49,7 @@ class Parameter extends LocalScopeVariable, @parameter { result = "p#" + this.getIndex().toString() } - override string getCanonicalQLClass() { result = "Parameter" } + override string getAPrimaryQlClass() { result = "Parameter" } /** * Gets the name of this parameter, including it's type. @@ -165,6 +169,7 @@ class Parameter extends LocalScopeVariable, @parameter { class ParameterIndex extends int { ParameterIndex() { exists(Parameter p | this = p.getIndex()) or - exists(Call c | exists(c.getArgument(this))) // permit indexing varargs + exists(Call c | exists(c.getArgument(this))) or // permit indexing varargs + this = -1 // used for `this` } } diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index d0104900d60..a9609922b74 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -33,11 +33,13 @@ class PreprocessorDirective extends Locatable, @preprocdirect { } } +private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_endif; + /** * A C/C++ preprocessor branch related directive: `#if`, `#ifdef`, * `#ifndef`, `#elif`, `#else` or `#endif`. */ -abstract class PreprocessorBranchDirective extends PreprocessorDirective { +class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective { /** * Gets the `#if`, `#ifdef` or `#ifndef` directive which matches this * branching directive. @@ -152,7 +154,7 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if { class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { override string toString() { result = "#ifdef " + this.getHead() } - override string getCanonicalQLClass() { result = "PreprocessorIfdef" } + override string getAPrimaryQlClass() { result = "PreprocessorIfdef" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index 9f69d564457..fb5232b3008 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -1,3 +1,11 @@ +/** + * Provides queries to pretty-print a C++ AST as a graph. + * + * By default, this will print the AST for all functions in the database. To change this behavior, + * extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions + * you wish to view the AST for. + */ + import cpp private import semmle.code.cpp.Print @@ -7,6 +15,9 @@ private newtype TPrintASTConfiguration = MkPrintASTConfiguration() * The query can extend this class to control which functions are printed. */ class PrintASTConfiguration extends TPrintASTConfiguration { + /** + * Gets a textual representation of this `PrintASTConfiguration`. + */ string toString() { result = "PrintASTConfiguration" } /** @@ -96,6 +107,9 @@ private newtype TPrintASTNode = * A node in the output tree. */ class PrintASTNode extends TPrintASTNode { + /** + * Gets a textual representation of this node in the PrintAST output tree. + */ abstract string toString(); /** @@ -155,7 +169,7 @@ class PrintASTNode extends TPrintASTNode { * Retrieves the canonical QL class(es) for entity `el` */ private string qlClass(ElementBase el) { - result = "[" + concat(el.getCanonicalQLClass(), ",") + "] " + result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] " // Alternative implementation -- do not delete. It is useful for QL class discovery. //result = "["+ concat(el.getAQlClass(), ",") + "] " } @@ -208,6 +222,9 @@ class ExprNode extends ASTNode { result = expr.getValueCategoryString() } + /** + * Gets the value of this expression, if it is a constant. + */ string getValue() { result = expr.getValue() } } @@ -373,6 +390,9 @@ class ParametersNode extends PrintASTNode, TParametersNode { override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) } + /** + * Gets the `Function` for which this node represents the parameters. + */ final Function getFunction() { result = func } } @@ -392,6 +412,9 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers result.getAST() = ctor.getInitializer(childIndex) } + /** + * Gets the `Constructor` for which this node represents the initializer list. + */ final Constructor getConstructor() { result = ctor } } @@ -411,6 +434,9 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo result.getAST() = dtor.getDestruction(childIndex) } + /** + * Gets the `Destructor` for which this node represents the destruction list. + */ final Destructor getDestructor() { result = dtor } } @@ -464,6 +490,9 @@ class FunctionNode extends ASTNode { key = "semmle.order" and result = getOrder().toString() } + /** + * Gets the `Function` this node represents. + */ final Function getFunction() { result = func } } @@ -499,11 +528,16 @@ class ArrayAggregateLiteralNode extends ExprNode { } } +/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ query predicate nodes(PrintASTNode node, string key, string value) { node.shouldPrint() and value = node.getProperty(key) } +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the + * given `value`. + */ query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) { exists(int childIndex | source.shouldPrint() and @@ -517,6 +551,7 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri ) } +/** Holds if property `key` of the graph has the given `value`. */ query predicate graphProperties(string key, string value) { key = "semmle.graphKind" and value = "tree" } diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index f58f060623d..3d68fb374f1 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling specifiers and attributes. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.internal.ResolveClass @@ -12,7 +16,7 @@ class Specifier extends Element, @specifier { result instanceof UnknownDefaultLocation } - override string getCanonicalQLClass() { result = "Specifier" } + override string getAPrimaryQlClass() { result = "Specifier" } /** Gets the name of this specifier. */ string getName() { specifiers(underlyingElement(this), result) } @@ -33,7 +37,7 @@ class FunctionSpecifier extends Specifier { this.hasName("explicit") } - override string getCanonicalQLClass() { result = "FunctionSpecifier)" } + override string getAPrimaryQlClass() { result = "FunctionSpecifier)" } } /** @@ -49,7 +53,7 @@ class StorageClassSpecifier extends Specifier { this.hasName("mutable") } - override string getCanonicalQLClass() { result = "StorageClassSpecifier" } + override string getAPrimaryQlClass() { result = "StorageClassSpecifier" } } /** @@ -104,7 +108,7 @@ class AccessSpecifier extends Specifier { ) } - override string getCanonicalQLClass() { result = "AccessSpecifier" } + override string getAPrimaryQlClass() { result = "AccessSpecifier" } } /** @@ -234,7 +238,7 @@ class FormatAttribute extends GnuAttribute { ) } - override string getCanonicalQLClass() { result = "FormatAttribute" } + override string getAPrimaryQlClass() { result = "FormatAttribute" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Struct.qll b/cpp/ql/src/semmle/code/cpp/Struct.qll index 6b95cdba1bd..50a208894b4 100644 --- a/cpp/ql/src/semmle/code/cpp/Struct.qll +++ b/cpp/ql/src/semmle/code/cpp/Struct.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `struct`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Class @@ -18,7 +22,7 @@ import semmle.code.cpp.Class class Struct extends Class { Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Struct" } + override string getAPrimaryQlClass() { result = "Struct" } override string explain() { result = "struct " + this.getName() } @@ -39,9 +43,7 @@ class Struct extends Class { class LocalStruct extends Struct { LocalStruct() { isLocal() } - override string getCanonicalQLClass() { - not this instanceof LocalUnion and result = "LocalStruct" - } + override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" } } /** @@ -58,7 +60,7 @@ class LocalStruct extends Struct { class NestedStruct extends Struct { NestedStruct() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedUnion and result = "NestedStruct" } diff --git a/cpp/ql/src/semmle/code/cpp/TestFile.qll b/cpp/ql/src/semmle/code/cpp/TestFile.qll index 4348bddf59c..b9e3fe3a614 100644 --- a/cpp/ql/src/semmle/code/cpp/TestFile.qll +++ b/cpp/ql/src/semmle/code/cpp/TestFile.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for identifying files that contain test cases. It is often + * desirable to exclude these files from analysis. + */ + import semmle.code.cpp.File /** diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 55eb4f27d3d..8273d0440d5 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -1,5 +1,8 @@ +/** + * Provides a hierarchy of classes for modeling C/C++ types. + */ + import semmle.code.cpp.Element -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass @@ -322,7 +325,7 @@ class BuiltInType extends Type, @builtintype { class ErroneousType extends BuiltInType { ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) } - override string getCanonicalQLClass() { result = "ErroneousType" } + override string getAPrimaryQlClass() { result = "ErroneousType" } } /** @@ -342,7 +345,7 @@ class ErroneousType extends BuiltInType { class UnknownType extends BuiltInType { UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) } - override string getCanonicalQLClass() { result = "UnknownType" } + override string getAPrimaryQlClass() { result = "UnknownType" } } private predicate isArithmeticType(@builtintype type, int kind) { @@ -361,7 +364,7 @@ private predicate isArithmeticType(@builtintype type, int kind) { class ArithmeticType extends BuiltInType { ArithmeticType() { isArithmeticType(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "ArithmeticType" } + override string getAPrimaryQlClass() { result = "ArithmeticType" } } private predicate isIntegralType(@builtintype type, int kind) { @@ -561,7 +564,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType { class BoolType extends IntegralType { BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) } - override string getCanonicalQLClass() { result = "BoolType" } + override string getAPrimaryQlClass() { result = "BoolType" } } /** @@ -586,7 +589,7 @@ abstract class CharType extends IntegralType { } class PlainCharType extends CharType { PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) } - override string getCanonicalQLClass() { result = "PlainCharType" } + override string getAPrimaryQlClass() { result = "PlainCharType" } } /** @@ -599,7 +602,7 @@ class PlainCharType extends CharType { class UnsignedCharType extends CharType { UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) } - override string getCanonicalQLClass() { result = "UnsignedCharType" } + override string getAPrimaryQlClass() { result = "UnsignedCharType" } } /** @@ -612,7 +615,7 @@ class UnsignedCharType extends CharType { class SignedCharType extends CharType { SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) } - override string getCanonicalQLClass() { result = "SignedCharType" } + override string getAPrimaryQlClass() { result = "SignedCharType" } } /** @@ -629,7 +632,7 @@ class ShortType extends IntegralType { builtintypes(underlyingElement(this), _, 10, _, _, _) } - override string getCanonicalQLClass() { result = "ShortType" } + override string getAPrimaryQlClass() { result = "ShortType" } } /** @@ -646,7 +649,7 @@ class IntType extends IntegralType { builtintypes(underlyingElement(this), _, 13, _, _, _) } - override string getCanonicalQLClass() { result = "IntType" } + override string getAPrimaryQlClass() { result = "IntType" } } /** @@ -663,7 +666,7 @@ class LongType extends IntegralType { builtintypes(underlyingElement(this), _, 16, _, _, _) } - override string getCanonicalQLClass() { result = "LongType" } + override string getAPrimaryQlClass() { result = "LongType" } } /** @@ -680,7 +683,7 @@ class LongLongType extends IntegralType { builtintypes(underlyingElement(this), _, 19, _, _, _) } - override string getCanonicalQLClass() { result = "LongLongType" } + override string getAPrimaryQlClass() { result = "LongLongType" } } /** @@ -698,7 +701,7 @@ class Int128Type extends IntegralType { builtintypes(underlyingElement(this), _, 37, _, _, _) } - override string getCanonicalQLClass() { result = "Int128Type" } + override string getAPrimaryQlClass() { result = "Int128Type" } } private newtype TTypeDomain = @@ -894,7 +897,7 @@ class DecimalFloatingPointType extends FloatingPointType { class FloatType extends RealNumberType, BinaryFloatingPointType { FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) } - override string getCanonicalQLClass() { result = "FloatType" } + override string getAPrimaryQlClass() { result = "FloatType" } } /** @@ -906,7 +909,7 @@ class FloatType extends RealNumberType, BinaryFloatingPointType { class DoubleType extends RealNumberType, BinaryFloatingPointType { DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) } - override string getCanonicalQLClass() { result = "DoubleType" } + override string getAPrimaryQlClass() { result = "DoubleType" } } /** @@ -918,7 +921,7 @@ class DoubleType extends RealNumberType, BinaryFloatingPointType { class LongDoubleType extends RealNumberType, BinaryFloatingPointType { LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) } - override string getCanonicalQLClass() { result = "LongDoubleType" } + override string getAPrimaryQlClass() { result = "LongDoubleType" } } /** @@ -930,7 +933,7 @@ class LongDoubleType extends RealNumberType, BinaryFloatingPointType { class Float128Type extends RealNumberType, BinaryFloatingPointType { Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) } - override string getCanonicalQLClass() { result = "Float128Type" } + override string getAPrimaryQlClass() { result = "Float128Type" } } /** @@ -942,7 +945,7 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType { class Decimal32Type extends RealNumberType, DecimalFloatingPointType { Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal32Type" } + override string getAPrimaryQlClass() { result = "Decimal32Type" } } /** @@ -954,7 +957,7 @@ class Decimal32Type extends RealNumberType, DecimalFloatingPointType { class Decimal64Type extends RealNumberType, DecimalFloatingPointType { Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal64Type" } + override string getAPrimaryQlClass() { result = "Decimal64Type" } } /** @@ -966,7 +969,7 @@ class Decimal64Type extends RealNumberType, DecimalFloatingPointType { class Decimal128Type extends RealNumberType, DecimalFloatingPointType { Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal128Type" } + override string getAPrimaryQlClass() { result = "Decimal128Type" } } /** @@ -978,7 +981,7 @@ class Decimal128Type extends RealNumberType, DecimalFloatingPointType { class VoidType extends BuiltInType { VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) } - override string getCanonicalQLClass() { result = "VoidType" } + override string getAPrimaryQlClass() { result = "VoidType" } } /** @@ -994,7 +997,7 @@ class VoidType extends BuiltInType { class WideCharType extends IntegralType { WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) } - override string getCanonicalQLClass() { result = "WideCharType" } + override string getAPrimaryQlClass() { result = "WideCharType" } } /** @@ -1006,7 +1009,7 @@ class WideCharType extends IntegralType { class Char8Type extends IntegralType { Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) } - override string getCanonicalQLClass() { result = "Char8Type" } + override string getAPrimaryQlClass() { result = "Char8Type" } } /** @@ -1018,7 +1021,7 @@ class Char8Type extends IntegralType { class Char16Type extends IntegralType { Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) } - override string getCanonicalQLClass() { result = "Char16Type" } + override string getAPrimaryQlClass() { result = "Char16Type" } } /** @@ -1030,7 +1033,7 @@ class Char16Type extends IntegralType { class Char32Type extends IntegralType { Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) } - override string getCanonicalQLClass() { result = "Char32Type" } + override string getAPrimaryQlClass() { result = "Char32Type" } } /** @@ -1045,7 +1048,7 @@ class Char32Type extends IntegralType { class NullPointerType extends BuiltInType { NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) } - override string getCanonicalQLClass() { result = "NullPointerType" } + override string getAPrimaryQlClass() { result = "NullPointerType" } } /** @@ -1080,22 +1083,46 @@ class DerivedType extends Type, @derivedtype { override Type stripType() { result = getBaseType().stripType() } - predicate isAutoReleasing() { + /** + * Holds if this type has the `__autoreleasing` specifier or if it points to + * a type with the `__autoreleasing` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isAutoReleasing() { this.hasSpecifier("__autoreleasing") or this.(PointerType).getBaseType().hasSpecifier("__autoreleasing") } - predicate isStrong() { + /** + * Holds if this type has the `__strong` specifier or if it points to + * a type with the `__strong` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isStrong() { this.hasSpecifier("__strong") or this.(PointerType).getBaseType().hasSpecifier("__strong") } - predicate isUnsafeRetained() { + /** + * Holds if this type has the `__unsafe_unretained` specifier or if it points + * to a type with the `__unsafe_unretained` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isUnsafeRetained() { this.hasSpecifier("__unsafe_unretained") or this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained") } - predicate isWeak() { + /** + * Holds if this type has the `__weak` specifier or if it points to + * a type with the `__weak` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isWeak() { this.hasSpecifier("__weak") or this.(PointerType).getBaseType().hasSpecifier("__weak") } @@ -1109,7 +1136,7 @@ class DerivedType extends Type, @derivedtype { * ``` */ class Decltype extends Type, @decltype { - override string getCanonicalQLClass() { result = "Decltype" } + override string getAPrimaryQlClass() { result = "Decltype" } /** * The expression whose type is being obtained by this decltype. @@ -1182,7 +1209,7 @@ class Decltype extends Type, @decltype { class PointerType extends DerivedType { PointerType() { derivedtypes(underlyingElement(this), _, 1, _) } - override string getCanonicalQLClass() { result = "PointerType" } + override string getAPrimaryQlClass() { result = "PointerType" } override int getPointerIndirectionLevel() { result = 1 + this.getBaseType().getPointerIndirectionLevel() @@ -1208,7 +1235,7 @@ class ReferenceType extends DerivedType { derivedtypes(underlyingElement(this), _, 2, _) or derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "ReferenceType" } + override string getAPrimaryQlClass() { result = "ReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1235,7 +1262,7 @@ class ReferenceType extends DerivedType { class LValueReferenceType extends ReferenceType { LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) } - override string getCanonicalQLClass() { result = "LValueReferenceType" } + override string getAPrimaryQlClass() { result = "LValueReferenceType" } } /** @@ -1251,7 +1278,7 @@ class LValueReferenceType extends ReferenceType { class RValueReferenceType extends ReferenceType { RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "RValueReferenceType" } + override string getAPrimaryQlClass() { result = "RValueReferenceType" } override string explain() { result = "rvalue " + super.explain() } } @@ -1266,7 +1293,7 @@ class RValueReferenceType extends ReferenceType { class SpecifiedType extends DerivedType { SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) } - override string getCanonicalQLClass() { result = "SpecifiedType" } + override string getAPrimaryQlClass() { result = "SpecifiedType" } override int getSize() { result = this.getBaseType().getSize() } @@ -1314,8 +1341,12 @@ class SpecifiedType extends DerivedType { class ArrayType extends DerivedType { ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) } - override string getCanonicalQLClass() { result = "ArrayType" } + override string getAPrimaryQlClass() { result = "ArrayType" } + /** + * Holds if this array is declared to be of a constant size. See + * `getArraySize` and `getByteSize` to get the size of the array. + */ predicate hasArraySize() { arraysizes(underlyingElement(this), _, _, _) } /** @@ -1381,7 +1412,7 @@ class GNUVectorType extends DerivedType { */ int getNumElements() { arraysizes(underlyingElement(this), result, _, _) } - override string getCanonicalQLClass() { result = "GNUVectorType" } + override string getAPrimaryQlClass() { result = "GNUVectorType" } /** * Gets the size, in bytes, of this vector type. @@ -1412,7 +1443,7 @@ class GNUVectorType extends DerivedType { class FunctionPointerType extends FunctionPointerIshType { FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) } - override string getCanonicalQLClass() { result = "FunctionPointerType" } + override string getAPrimaryQlClass() { result = "FunctionPointerType" } override int getPointerIndirectionLevel() { result = 1 } @@ -1430,7 +1461,7 @@ class FunctionPointerType extends FunctionPointerIshType { class FunctionReferenceType extends FunctionPointerIshType { FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) } - override string getCanonicalQLClass() { result = "FunctionReferenceType" } + override string getAPrimaryQlClass() { result = "FunctionReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1519,7 +1550,7 @@ class PointerToMemberType extends Type, @ptrtomember { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "PointerToMemberType" } + override string getAPrimaryQlClass() { result = "PointerToMemberType" } /** the name of this type */ override string getName() { result = "..:: *" } @@ -1564,16 +1595,25 @@ class RoutineType extends Type, @routinetype { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "RoutineType" } + override string getAPrimaryQlClass() { result = "RoutineType" } override string getName() { result = "..()(..)" } + /** + * Gets the type of the `n`th parameter to this routine. + */ Type getParameterType(int n) { routinetypeargs(underlyingElement(this), n, unresolveElement(result)) } + /** + * Gets the type of a parameter to this routine. + */ Type getAParameterType() { routinetypeargs(underlyingElement(this), _, unresolveElement(result)) } + /** + * Gets the return type of this routine. + */ Type getReturnType() { routinetypes(underlyingElement(this), unresolveElement(result)) } override string explain() { @@ -1632,7 +1672,7 @@ class TemplateParameter extends UserType { usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateParameter" } override predicate involvesTemplateParameter() { any() } } @@ -1650,7 +1690,7 @@ class TemplateParameter extends UserType { class TemplateTemplateParameter extends TemplateParameter { TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateTemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" } } /** @@ -1662,7 +1702,7 @@ class TemplateTemplateParameter extends TemplateParameter { class AutoType extends TemplateParameter { AutoType() { usertypes(underlyingElement(this), "auto", 7) } - override string getCanonicalQLClass() { result = "AutoType" } + override string getAPrimaryQlClass() { result = "AutoType" } override Location getLocation() { suppressUnusedThis(this) and @@ -1698,7 +1738,7 @@ private predicate suppressUnusedThis(Type t) { any() } class TypeMention extends Locatable, @type_mention { override string toString() { result = "type mention" } - override string getCanonicalQLClass() { result = "TypeMention" } + override string getAPrimaryQlClass() { result = "TypeMention" } /** * Gets the type being referenced by this type mention. diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index 504333aeedc..aaf452ce4bb 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling typedefs and type aliases. + */ + import semmle.code.cpp.Type private import semmle.code.cpp.internal.ResolveClass @@ -55,7 +59,7 @@ class TypedefType extends UserType { class CTypedefType extends TypedefType { CTypedefType() { usertypes(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { result = "CTypedefType" } + override string getAPrimaryQlClass() { result = "CTypedefType" } override string explain() { result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -71,7 +75,7 @@ class CTypedefType extends TypedefType { class UsingAliasTypedefType extends TypedefType { UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) } - override string getCanonicalQLClass() { result = "UsingAliasTypedefType" } + override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" } override string explain() { result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -88,7 +92,7 @@ class UsingAliasTypedefType extends TypedefType { class LocalTypedefType extends TypedefType { LocalTypedefType() { isLocal() } - override string getCanonicalQLClass() { result = "LocalTypedefType" } + override string getAPrimaryQlClass() { result = "LocalTypedefType" } } /** @@ -101,7 +105,7 @@ class LocalTypedefType extends TypedefType { class NestedTypedefType extends TypedefType { NestedTypedefType() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedTypedefType" } + override string getAPrimaryQlClass() { result = "NestedTypedefType" } /** * DEPRECATED: use `.hasSpecifier("private")` instead. diff --git a/cpp/ql/src/semmle/code/cpp/Union.qll b/cpp/ql/src/semmle/code/cpp/Union.qll index f1c033438ba..6dcb2f0796c 100644 --- a/cpp/ql/src/semmle/code/cpp/Union.qll +++ b/cpp/ql/src/semmle/code/cpp/Union.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `union`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Struct @@ -13,7 +17,7 @@ import semmle.code.cpp.Struct class Union extends Struct { Union() { usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Union" } + override string getAPrimaryQlClass() { result = "Union" } override string explain() { result = "union " + this.getName() } @@ -35,7 +39,7 @@ class Union extends Struct { class LocalUnion extends Union { LocalUnion() { isLocal() } - override string getCanonicalQLClass() { result = "LocalUnion" } + override string getAPrimaryQlClass() { result = "LocalUnion" } } /** @@ -53,7 +57,7 @@ class LocalUnion extends Union { class NestedUnion extends Union { NestedUnion() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedUnion" } + override string getAPrimaryQlClass() { result = "NestedUnion" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index 4484cde84de..2ab0603f06c 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -1,6 +1,10 @@ +/** + * Provides classes for modeling user-defined types such as classes, typedefs + * and enums. + */ + import semmle.code.cpp.Declaration import semmle.code.cpp.Type -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass @@ -20,7 +24,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ */ override string getName() { usertypes(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "UserType" } + override string getAPrimaryQlClass() { result = "UserType" } /** * Gets the simple name of this type, without any template parameters. For example @@ -84,6 +88,9 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * type exactly - but this is not apparent from its subclasses */ + /** + * Gets a child declaration within this user-defined type. + */ Declaration getADeclaration() { none() } override string explain() { result = this.getName() } @@ -104,7 +111,7 @@ class TypeDeclarationEntry extends DeclarationEntry, @type_decl { override string getName() { result = getType().getName() } - override string getCanonicalQLClass() { result = "TypeDeclarationEntry" } + override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" } /** * The type which is being declared or defined. diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 4d546a736dc..bc2067500cc 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling variables and their declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.exprs.Access import semmle.code.cpp.Initializer @@ -28,7 +32,7 @@ private import semmle.code.cpp.internal.ResolveClass * can have multiple declarations. */ class Variable extends Declaration, @variable { - override string getCanonicalQLClass() { result = "Variable" } + override string getAPrimaryQlClass() { result = "Variable" } /** Gets the initializer of this variable, if any. */ Initializer getInitializer() { result.getDeclaration() = this } @@ -186,7 +190,7 @@ class Variable extends Declaration, @variable { class VariableDeclarationEntry extends DeclarationEntry, @var_decl { override Variable getDeclaration() { result = getVariable() } - override string getCanonicalQLClass() { result = "VariableDeclarationEntry" } + override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" } /** * Gets the variable which is being declared or defined. @@ -245,7 +249,7 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl { class ParameterDeclarationEntry extends VariableDeclarationEntry { ParameterDeclarationEntry() { param_decl_bind(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "ParameterDeclarationEntry" } + override string getAPrimaryQlClass() { result = "ParameterDeclarationEntry" } /** * Gets the function declaration or definition which this parameter @@ -260,24 +264,33 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ int getIndex() { param_decl_bind(underlyingElement(this), result, _) } + private string getAnonymousParameterDescription() { + not exists(getName()) and + exists(string idx | + idx = + ((getIndex() + 1).toString() + "th") + .replaceAll("1th", "1st") + .replaceAll("2th", "2nd") + .replaceAll("3th", "3rd") + .replaceAll("11st", "11th") + .replaceAll("12nd", "12th") + .replaceAll("13rd", "13th") and + if exists(getCanonicalName()) + then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" + else result = "declaration of " + idx + " parameter" + ) + } + override string toString() { - if exists(getName()) - then result = super.toString() - else - exists(string idx | - idx = - ((getIndex() + 1).toString() + "th") - .replaceAll("1th", "1st") - .replaceAll("2th", "2nd") - .replaceAll("3th", "3rd") - .replaceAll("11st", "11th") - .replaceAll("12nd", "12th") - .replaceAll("13rd", "13th") - | - if exists(getCanonicalName()) - then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" - else result = "declaration of " + idx + " parameter" - ) + isDefinition() and + result = "definition of " + getName() + or + not isDefinition() and + if getName() = getCanonicalName() + then result = "declaration of " + getName() + else result = "declaration of " + getCanonicalName() + " as " + getName() + or + result = getAnonymousParameterDescription() } /** @@ -312,7 +325,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ class LocalScopeVariable extends Variable, @localscopevariable { /** Gets the function to which this variable belongs. */ - /*abstract*/ Function getFunction() { none() } + Function getFunction() { none() } // overridden in subclasses } /** @@ -350,7 +363,7 @@ class StackVariable extends LocalScopeVariable { * A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`. */ class LocalVariable extends LocalScopeVariable, @localvariable { - override string getCanonicalQLClass() { result = "LocalVariable" } + override string getAPrimaryQlClass() { result = "LocalVariable" } override string getName() { localvariables(underlyingElement(this), _, result) } @@ -451,7 +464,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { exists(Namespace n | namespacembrs(unresolveElement(n), underlyingElement(this))) } - override string getCanonicalQLClass() { result = "NamespaceVariable" } + override string getAPrimaryQlClass() { result = "NamespaceVariable" } } /** @@ -472,7 +485,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { class GlobalVariable extends GlobalOrNamespaceVariable { GlobalVariable() { not this instanceof NamespaceVariable } - override string getCanonicalQLClass() { result = "GlobalVariable" } + override string getAPrimaryQlClass() { result = "GlobalVariable" } } /** @@ -492,7 +505,7 @@ class GlobalVariable extends GlobalOrNamespaceVariable { class MemberVariable extends Variable, @membervariable { MemberVariable() { this.isMember() } - override string getCanonicalQLClass() { result = "MemberVariable" } + override string getAPrimaryQlClass() { result = "MemberVariable" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll index f584a8e4802..253a2767077 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll @@ -6,7 +6,7 @@ import semmle.code.cpp.Type class CharPointerType extends PointerType { CharPointerType() { this.getBaseType() instanceof CharType } - override string getCanonicalQLClass() { result = "CharPointerType" } + override string getAPrimaryQlClass() { result = "CharPointerType" } } /** @@ -15,7 +15,7 @@ class CharPointerType extends PointerType { class IntPointerType extends PointerType { IntPointerType() { this.getBaseType() instanceof IntType } - override string getCanonicalQLClass() { result = "IntPointerType" } + override string getAPrimaryQlClass() { result = "IntPointerType" } } /** @@ -24,7 +24,7 @@ class IntPointerType extends PointerType { class VoidPointerType extends PointerType { VoidPointerType() { this.getBaseType() instanceof VoidType } - override string getCanonicalQLClass() { result = "VoidPointerType" } + override string getAPrimaryQlClass() { result = "VoidPointerType" } } /** @@ -36,7 +36,7 @@ class Size_t extends Type { this.hasName("size_t") } - override string getCanonicalQLClass() { result = "Size_t" } + override string getAPrimaryQlClass() { result = "Size_t" } } /** @@ -48,7 +48,7 @@ class Ssize_t extends Type { this.hasName("ssize_t") } - override string getCanonicalQLClass() { result = "Ssize_t" } + override string getAPrimaryQlClass() { result = "Ssize_t" } } /** @@ -60,7 +60,7 @@ class Ptrdiff_t extends Type { this.hasName("ptrdiff_t") } - override string getCanonicalQLClass() { result = "Ptrdiff_t" } + override string getAPrimaryQlClass() { result = "Ptrdiff_t" } } /** @@ -72,7 +72,7 @@ class Intmax_t extends Type { this.hasName("intmax_t") } - override string getCanonicalQLClass() { result = "Intmax_t" } + override string getAPrimaryQlClass() { result = "Intmax_t" } } /** @@ -84,7 +84,7 @@ class Uintmax_t extends Type { this.hasName("uintmax_t") } - override string getCanonicalQLClass() { result = "Uintmax_t" } + override string getAPrimaryQlClass() { result = "Uintmax_t" } } /** @@ -100,7 +100,7 @@ class Wchar_t extends Type { this.hasName("wchar_t") } - override string getCanonicalQLClass() { result = "Wchar_t" } + override string getAPrimaryQlClass() { result = "Wchar_t" } } /** @@ -176,5 +176,5 @@ class MicrosoftInt64Type extends IntegralType { class BuiltInVarArgsList extends Type { BuiltInVarArgsList() { this.hasName("__builtin_va_list") } - override string getCanonicalQLClass() { result = "BuiltInVarArgsList" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsList" } } diff --git a/cpp/ql/src/semmle/code/cpp/commons/File.qll b/cpp/ql/src/semmle/code/cpp/commons/File.qll index 5808d704e38..acc5893d810 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/File.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/File.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying function calls that open or close a file. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index 32cea249214..3be11621b3b 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -20,7 +20,7 @@ class PrintfFormatAttribute extends FormatAttribute { * function by its use of the GNU `format` attribute. */ class AttributeFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "AttributeFormattingFunction" } + override string getAPrimaryQlClass() { result = "AttributeFormattingFunction" } AttributeFormattingFunction() { exists(PrintfFormatAttribute printf_attrib | @@ -73,7 +73,7 @@ predicate variadicFormatter(Function f, int formatParamIndex) { * string and a variable number of arguments. */ class UserDefinedFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "UserDefinedFormattingFunction" } + override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" } UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) } @@ -86,7 +86,7 @@ class UserDefinedFormattingFunction extends FormattingFunction { class FormattingFunctionCall extends Expr { FormattingFunctionCall() { this.(Call).getTarget() instanceof FormattingFunction } - override string getCanonicalQLClass() { result = "FormattingFunctionCall" } + override string getAPrimaryQlClass() { result = "FormattingFunctionCall" } /** * Gets the formatting function being called. diff --git a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll index 92c09a3e666..b54ff6d66e3 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides a class for calculating the possible length of string expressions. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.controlflow.SSA diff --git a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll index c680cfb073e..c7641385393 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll @@ -23,8 +23,7 @@ abstract class MutexType extends Type { abstract predicate trylockAccess(FunctionCall fc, Expr arg); /** - * Holds if `fc` is a call that unlocks mutex `arg` - * of this type. + * Holds if `fc` is a call that unlocks mutex `arg` of this type. */ abstract predicate unlockAccess(FunctionCall fc, Expr arg); @@ -38,8 +37,7 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that locks or tries to lock any - * mutex of this type. + * Gets a call that locks or tries to lock any mutex of this type. */ FunctionCall getLockAccess() { result = getMustlockAccess() or @@ -47,44 +45,44 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that always locks any mutex of this type. + * Gets a call that always locks any mutex of this type. */ FunctionCall getMustlockAccess() { this.mustlockAccess(result, _) } /** - * Holds if `fc` is a call that tries to lock any mutex of this type, + * Gets a call that tries to lock any mutex of this type, * by may return without success. */ FunctionCall getTrylockAccess() { this.trylockAccess(result, _) } /** - * Holds if `fc` is a call that unlocks any mutex of this type. + * Gets a call that unlocks any mutex of this type. */ FunctionCall getUnlockAccess() { this.unlockAccess(result, _) } /** - * DEPRECATED: use mustlockAccess(fc, arg) instead + * DEPRECATED: use mustlockAccess(fc, arg) instead. */ deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() } /** - * DEPRECATED: use trylockAccess(fc, arg) instead + * DEPRECATED: use trylockAccess(fc, arg) instead. */ deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() } /** - * DEPRECATED: use lockAccess(fc, arg) instead + * DEPRECATED: use lockAccess(fc, arg) instead. */ deprecated Function getLockFunction() { result = getLockAccess().getTarget() } /** - * DEPRECATED: use unlockAccess(fc, arg) instead + * DEPRECATED: use unlockAccess(fc, arg) instead. */ deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() } } /** - * A function that looks like a lock function. + * Gets a function that looks like a lock function. */ private Function mustlockCandidate() { exists(string name | name = result.getName() | @@ -94,7 +92,7 @@ private Function mustlockCandidate() { } /** - * A function that looks like a try-lock function. + * Gets a function that looks like a try-lock function. */ private Function trylockCandidate() { exists(string name | name = result.getName() | @@ -104,7 +102,7 @@ private Function trylockCandidate() { } /** - * A function that looks like an unlock function. + * Gets a function that looks like an unlock function. */ private Function unlockCandidate() { exists(string name | name = result.getName() | @@ -171,7 +169,10 @@ class DefaultMutexType extends MutexType { } } -/** Get the mutex argument of a call to lock or unlock. */ +/** + * Holds if `arg` is the mutex argument of a call to lock or unlock and + * `argType` is the type of the mutex. + */ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { argType = arg.getUnderlyingType().stripType() and ( @@ -184,18 +185,31 @@ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { // `MutexType.mustlockAccess`. } +/** + * Holds if `call` is a call that locks or tries to lock its argument `arg`. + */ predicate lockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getLockAccess()) } +/** + * Holds if `call` is a call that always locks its argument `arg`. + */ predicate mustlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getMustlockAccess()) } +/** + * Holds if `call` is a call that tries to lock its argument `arg`, but may + * return without success. + */ predicate trylockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getTrylockAccess()) } +/** + * Holds if `call` is a call that unlocks its argument `arg`. + */ predicate unlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getUnlockAccess()) } diff --git a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll index 3478eb87e28..f9f854b1aab 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll @@ -4,6 +4,11 @@ import cpp +/** + * Gets the number corresponding to the contents of `input` in base-8. + * Note: the first character of `input` must be `0`. For example: + * `parseOctal("012345") = 5349`. + */ bindingset[input] int parseOctal(string input) { input.charAt(0) = "0" and @@ -15,44 +20,77 @@ int parseOctal(string input) { ) } +/** Gets the number corresponding to the "set-user-ID on execute bit" in Unix. */ int s_isuid() { result = parseOctal("04000") } +/** Gets the number corresponding to the "set-group-ID on execute bit" in Unix. */ int s_isgid() { result = parseOctal("02000") } +/** Gets the number corresponding to the sticky bit in Unix. */ int s_isvtx() { result = parseOctal("01000") } +/** Gets the number corresponding to the read permission bit for owner of the file in Unix. */ int s_irusr() { result = parseOctal("0400") } +/** Gets the number corresponding to the write permission bit for owner of the file in Unix. */ int s_iwusr() { result = parseOctal("0200") } +/** Gets the number corresponding to the execute permission bit for owner of the file in Unix. */ int s_ixusr() { result = parseOctal("0100") } +/** Gets the number corresponding to the permissions `S_IRUSR | S_IWUSR | S_IXUSR` in Unix. */ int s_irwxu() { result = s_irusr().bitOr(s_iwusr()).bitOr(s_ixusr()) } +/** + * Gets the number corresponding to the read permission bit for the group + * owner of the file in Unix. + */ int s_irgrp() { result = s_irusr().bitShiftRight(3) } +/** + * Gets the number corresponding to the write permission bit for the group + * owner of the file in Unix. + */ int s_iwgrp() { result = s_iwusr().bitShiftRight(3) } +/** + * Gets the number corresponding to the execute permission bit for the group + * owner of the file in Unix. + */ int s_ixgrp() { result = s_ixusr().bitShiftRight(3) } +/** Gets the number corresponding to the permissions `S_IRGRP | S_IWGRP | S_IXGRP` in Unix. */ int s_irwxg() { result = s_irwxu().bitShiftRight(3) } +/** Gets the number corresponding to the read permission bit for other users in Unix. */ int s_iroth() { result = s_irgrp().bitShiftRight(3) } +/** Gets the number corresponding to the write permission bit for other users in Unix. */ int s_iwoth() { result = s_iwgrp().bitShiftRight(3) } +/** Gets the number corresponding to the execute-or-search permission bit for other users in Unix. */ int s_ixoth() { result = s_ixgrp().bitShiftRight(3) } +/** Gets the number corresponding to the permissions `S_IROTH | S_IWOTH | S_IXOTH` in Unix. */ int s_irwxo() { result = s_irwxg().bitShiftRight(3) } +/** + * Gets the number that can be used in a bitwise and with the file status flag + * to produce a number representing the file access mode. + */ int o_accmode() { result = parseOctal("0003") } +/** Gets the number corresponding to the read-only file access mode. */ int o_rdonly() { result = parseOctal("00") } +/** Gets the number corresponding to the write-only file access mode. */ int o_wronly() { result = parseOctal("01") } +/** Gets the number corresponding to the read-and-write file access mode. */ int o_rdwr() { result = parseOctal("02") } +/** Gets the number corresponding to the file creation flag O_CREAT on Linux. */ int o_creat() { result = parseOctal("0100") } +/** Gets the number corresponding to the file creation flag O_EXCL on Linux. */ int o_excl() { result = parseOctal("0200") } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll index 681d0b710f6..16947019f54 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control flow at the granularity of basic blocks. + * This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s. + */ + import cpp private import internal.PrimitiveBasicBlocks private import internal.ConstantExprs @@ -148,22 +153,37 @@ predicate bb_successor = bb_successor_cached/2; class BasicBlock extends ControlFlowNodeBase { BasicBlock() { basic_block_entry_node(this) } + /** Holds if this basic block contains `node`. */ predicate contains(ControlFlowNode node) { basic_block_member(node, this, _) } + /** Gets the `ControlFlowNode` at position `pos` in this basic block. */ ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) } + /** Gets a `ControlFlowNode` in this basic block. */ ControlFlowNode getANode() { basic_block_member(result, this, _) } + /** Gets a `BasicBlock` that is a direct successor of this basic block. */ BasicBlock getASuccessor() { bb_successor(this, result) } + /** Gets a `BasicBlock` that is a direct predecessor of this basic block. */ BasicBlock getAPredecessor() { bb_successor(result, this) } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is true. + */ BasicBlock getATrueSuccessor() { result.getStart() = this.getEnd().getATrueSuccessor() } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is false. + */ BasicBlock getAFalseSuccessor() { result.getStart() = this.getEnd().getAFalseSuccessor() } + /** Gets the final `ControlFlowNode` of this basic block. */ ControlFlowNode getEnd() { basic_block_member(result, this, bb_length(this) - 1) } + /** Gets the first `ControlFlowNode` of this basic block. */ ControlFlowNode getStart() { result = this } /** Gets the number of `ControlFlowNode`s in this basic block. */ @@ -192,6 +212,7 @@ class BasicBlock extends ControlFlowNodeBase { this.getEnd().getLocation().hasLocationInfo(endf, _, _, endl, endc) } + /** Gets the function containing this basic block. */ Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index 9174f474a8f..1f79d6c5bc2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control flow at the granularity of + * individual nodes in the control-flow graph. + */ + import cpp import BasicBlocks private import semmle.code.cpp.controlflow.internal.ConstantExprs @@ -29,8 +34,10 @@ private import semmle.code.cpp.controlflow.internal.CFG * `Handler`. There are no edges from function calls to `Handler`s. */ class ControlFlowNode extends Locatable, ControlFlowNodeBase { + /** Gets a direct successor of this control-flow node, if any. */ ControlFlowNode getASuccessor() { successors_adapted(this, result) } + /** Gets a direct predecessor of this control-flow node, if any. */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } /** Gets the function containing this control-flow node. */ @@ -71,6 +78,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { result = getASuccessor() } + /** Gets the `BasicBlock` containing this control-flow node. */ BasicBlock getBasicBlock() { result.getANode() = this } } @@ -86,10 +94,18 @@ import ControlFlowGraphPublic */ class ControlFlowNodeBase extends ElementBase, @cfgnode { } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is true. + */ predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGTrueSuccessor(n1, n2) } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is false. + */ predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGFalseSuccessor(n1, n2) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll index 99fb6966099..1a5d81ee9f3 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll @@ -15,14 +15,25 @@ import Dereferenced abstract class DataflowAnnotation extends string { DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" } + /** Holds if this annotation is the default annotation. */ abstract predicate isDefault(); + /** Holds if this annotation is generated when analyzing expression `e`. */ abstract predicate generatedOn(Expr e); + /** + * Holds if this annotation is generated for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate generatedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** + * Holds if this annotation is removed for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate killedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** Holds if expression `e` is given this annotation. */ predicate marks(Expr e) { this.generatedOn(e) and reachable(e) or @@ -31,6 +42,7 @@ abstract class DataflowAnnotation extends string { exists(LocalScopeVariable v | this.marks(v, e) and e = v.getAnAccess()) } + /** Holds if the variable `v` accessed in control-flow node `n` is given this annotation. */ predicate marks(LocalScopeVariable v, ControlFlowNode n) { v.getAnAccess().getEnclosingFunction().getBlock() = n and this.isDefault() @@ -57,6 +69,10 @@ abstract class DataflowAnnotation extends string { ) } + /** + * Holds if the variable `v` preserves this annotation when the control-flow + * edge `(src, dest)` is taken. + */ predicate preservedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(v, src) and src.getASuccessor() = dest and @@ -64,6 +80,10 @@ abstract class DataflowAnnotation extends string { not v.getAnAssignment() = src } + /** + * Holds if the variable `v` is assigned this annotation when `src` is an assignment + * expression that assigns to `v` and the control-flow edge `(src, dest)` is taken. + */ predicate assignedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(src.(AssignExpr).getRValue()) and src = v.getAnAssignment() and diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll index e7f304af382..f6eb0a8a645 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for reasoning about definitions and uses of variables. + */ + import cpp private import semmle.code.cpp.controlflow.StackVariableReachability private import semmle.code.cpp.dataflow.EscapesTree @@ -135,6 +139,7 @@ library class DefOrUse extends ControlFlowNodeBase { } } +/** A definition of a stack variable. */ library class Def extends DefOrUse { Def() { definition(_, this) } @@ -149,6 +154,7 @@ private predicate parameterIsOverwritten(Function f, Parameter p) { definitionBarrier(p, _) } +/** A definition of a parameter. */ library class ParameterDef extends DefOrUse { ParameterDef() { // Optimization: parameters that are not overwritten do not require @@ -162,6 +168,7 @@ library class ParameterDef extends DefOrUse { } } +/** A use of a stack variable. */ library class Use extends DefOrUse { Use() { useOfVar(_, this) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll index 69c5963af30..a667c39943f 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for detecting whether an expression dereferences a pointer. + */ + import cpp import Nullness diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll index 007c1f2ecfc..e7809358bce 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about guards and the control + * flow elements controlled by those guards. + */ + import cpp import semmle.code.cpp.controlflow.BasicBlocks import semmle.code.cpp.controlflow.SSA diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 1f7b3b09946..656496325af 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about guards and the control + * flow elements controlled by those guards. + */ + import cpp import semmle.code.cpp.ir.IR @@ -8,6 +13,7 @@ import semmle.code.cpp.ir.IR * has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock` * and the `IRBlock`. */ +pragma[noinline] private predicate isUnreachedBlock(IRBlock block) { block.getFirstInstruction() instanceof UnreachedInstruction } @@ -32,7 +38,7 @@ class GuardCondition extends Expr { } /** - * Holds if this condition controls `block`, meaning that `block` is only + * Holds if this condition controls `controlled`, meaning that `controlled` is only * entered if the value of this condition is `testIsTrue`. * * Illustration: @@ -253,7 +259,7 @@ class IRGuardCondition extends Instruction { IRGuardCondition() { branch = get_branch_for_condition(this) } /** - * Holds if this condition controls `block`, meaning that `block` is only + * Holds if this condition controls `controlled`, meaning that `controlled` is only * entered if the value of this condition is `testIsTrue`. * * Illustration: @@ -290,18 +296,22 @@ class IRGuardCondition extends Instruction { ) } + /** + * Holds if the control-flow edge `(pred, succ)` may be taken only if + * the value of this condition is `testIsTrue`. + */ cached predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { pred.getASuccessor() = succ and controls(pred, testIsTrue) or - hasBranchEdge(succ, testIsTrue) and + succ = getBranchSuccessor(testIsTrue) and branch.getCondition() = this and branch.getBlock() = pred } /** - * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. + * Gets the block to which `branch` jumps directly when this condition is `testIsTrue`. * * This predicate is intended to help with situations in which an inference can only be made * based on an edge between a block with multiple successors and a block with multiple @@ -315,14 +325,14 @@ class IRGuardCondition extends Instruction { * return x; * ``` */ - private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) { + private IRBlock getBranchSuccessor(boolean testIsTrue) { branch.getCondition() = this and ( testIsTrue = true and - succ.getFirstInstruction() = branch.getTrueSuccessor() + result.getFirstInstruction() = branch.getTrueSuccessor() or testIsTrue = false and - succ.getFirstInstruction() = branch.getFalseSuccessor() + result.getFirstInstruction() = branch.getFalseSuccessor() ) } @@ -396,20 +406,78 @@ class IRGuardCondition extends Instruction { */ private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { not isUnreachedBlock(controlled) and - exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | - exists(IRBlock succ | - testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() + // + // For this block to control the block `controlled` with `testIsTrue` the + // following must hold: Execution must have passed through the test; that + // is, `this` must strictly dominate `controlled`. Execution must have + // passed through the `testIsTrue` edge leaving `this`. + // + // Although "passed through the true edge" implies that + // `getBranchSuccessor(true)` dominates `controlled`, the reverse is not + // true, as flow may have passed through another edge to get to + // `getBranchSuccessor(true)`, so we need to assert that + // `getBranchSuccessor(true)` dominates `controlled` *and* that all + // predecessors of `getBranchSuccessor(true)` are either `this` or + // dominated by `getBranchSuccessor(true)`. + // + // For example, in the following snippet: + // + // if (x) + // controlled; + // false_successor; + // uncontrolled; + // + // `false_successor` dominates `uncontrolled`, but not all of its + // predecessors are `this` (`if (x)`) or dominated by itself. Whereas in + // the following code: + // + // if (x) + // while (controlled) + // also_controlled; + // false_successor; + // uncontrolled; + // + // the block `while (controlled)` is controlled because all of its + // predecessors are `this` (`if (x)`) or (in the case of `also_controlled`) + // dominated by itself. + // + // The additional constraint on the predecessors of the test successor implies + // that `this` strictly dominates `controlled` so that isn't necessary to check + // directly. + exists(IRBlock succ | + succ = this.getBranchSuccessor(testIsTrue) and + this.hasDominatingEdgeTo(succ) and + succ.dominates(controlled) + ) + } + + /** + * Holds if `(this, succ)` is an edge that dominates `succ`, that is, all other + * predecessors of `succ` are dominated by `succ`. This implies that `this` is the + * immediate dominator of `succ`. + * + * This is a necessary and sufficient condition for an edge to dominate anything, + * and in particular `bb1.hasDominatingEdgeTo(bb2) and bb2.dominates(bb3)` means + * that the edge `(bb1, bb2)` dominates `bb3`. + */ + private predicate hasDominatingEdgeTo(IRBlock succ) { + exists(IRBlock branchBlock | branchBlock = this.getBranchBlock() | + branchBlock.immediatelyDominates(succ) and + branchBlock.getASuccessor() = succ and + forall(IRBlock pred | pred = succ.getAPredecessor() and pred != branchBlock | + succ.dominates(pred) or - testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() - | - branch.getCondition() = this and - succ.dominates(controlled) and - forall(IRBlock pred | pred.getASuccessor() = succ | - pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() - ) + // An unreachable `pred` is vacuously dominated by `succ` since all + // paths from the entry to `pred` go through `succ`. Such vacuous + // dominance is not included in the `dominates` predicate since that + // could cause quadratic blow-up. + not pred.isReachableFromFunctionEntry() ) ) } + + pragma[noinline] + private IRBlock getBranchBlock() { result = branch.getBlock() } } private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) { diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll index caaa5b54e8c..69d2166a1d2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with null values and checks for nullness. + */ + import cpp import DefinitionsAndUses diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll index 4e2e018eda3..5c0f6b3ac14 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll @@ -1,7 +1,15 @@ +/** + * Provides classes and predicates for SSA representation (Static Single Assignment form). + */ + import cpp import semmle.code.cpp.controlflow.Dominance import SSAUtils +/** + * The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA. + * This class provides the standard SSA logic. + */ library class StandardSSA extends SSAHelper { StandardSSA() { this = 0 } } @@ -50,11 +58,13 @@ class SsaDefinition extends ControlFlowNodeBase { */ ControlFlowNode getDefinition() { result = this } + /** Gets the `BasicBlock` containing this definition. */ BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Holds if this definition is a phi node for variable `v`. */ predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) } + /** Gets the location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } /** Holds if the SSA variable `(this, p)` is defined by parameter `p`. */ diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll index b9b34a1d68c..3ae1ed11e6d 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for use in the SSA library. + */ + import cpp import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSA // must be imported for proper caching of SSAHelper diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll index 696184620e3..6c50d254faa 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for working with local (intra-procedural) control-flow + * reachability involving stack variables. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll index dafcd1fdd97..fa9d2e94081 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll @@ -168,6 +168,7 @@ class SubBasicBlock extends ControlFlowNodeBase { /** Gets the first control-flow node in this `SubBasicBlock`. */ ControlFlowNode getStart() { result = this } + /** Gets the function that contains this `SubBasicBlock`. */ pragma[noinline] Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 22e39f0b907..eaa1581078b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -4,6 +4,14 @@ * passed to a function, or similar. */ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp /** @@ -11,15 +19,13 @@ private import cpp * template functions, these functions are essentially casts, so we treat them * as such. */ -private predicate stdIdentityFunction(Function f) { - f.getNamespace().getParentNamespace() instanceof GlobalNamespace and - f.getNamespace().getName() = "std" and - ( - f.getName() = "move" - or - f.getName() = "forward" - ) -} +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) { lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted() @@ -91,12 +97,17 @@ private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { } private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { - // This probably cannot happen. It would require an expression to be - // converted to a reference and back again without an intermediate variable - // assignment. referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) } +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { referenceOut = any(FunctionCall call | @@ -145,6 +156,12 @@ private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) { pointerToPointerStep(prev, pointer) ) or + // reference -> pointer + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToPointerStep(prev, pointer) + ) + or // lvalue -> pointer exists(Expr prev | lvalueFromVariableAccess(va, prev) and @@ -169,7 +186,8 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) private predicate addressMayEscapeAt(Expr e) { exists(Call call | e = call.getAnArgument().getFullyConverted() and - not stdIdentityFunction(call.getTarget()) + not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) or e = call.getQualifier().getFullyConverted() and e.getUnderlyingType() instanceof PointerType diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll new file mode 100644 index 00000000000..b3f8cd02828 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -0,0 +1,247 @@ +/** + * Provides a local analysis for identifying where a variable address + * is effectively taken. Array-like offsets are allowed to pass through but + * not field-like offsets. + * + * This library is specialized to meet the needs of `FlowVar.qll`. + */ + +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + +private import cpp + +/** + * Holds if `f` is an instantiation of the `std::move` or `std::forward` + * template functions, these functions are essentially casts, so we treat them + * as such. + */ +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } + +private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { + lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) + or + // When an object is implicitly converted to a reference to one of its base + // classes, it gets two `Conversion`s: there is first an implicit + // `CStyleCast` to its base class followed by a `ReferenceToExpr` to a + // reference to its base class. Whereas an explicit cast to the base class + // would produce an rvalue, which would not be convertible to an lvalue + // reference, this implicit cast instead produces an lvalue. The following + // case ensures that we propagate the property of being an lvalue through + // such casts. + lvalueIn.getConversion() = lvalueOut and + lvalueOut.(CStyleCast).isImplicit() + or + // C++ only + lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted() + or + // C++ only + lvalueIn = lvalueOut.(Assignment).getLValue().getFullyConverted() +} + +private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) { + pointerIn = lvalueOut.(ArrayExpr).getArrayBase().getFullyConverted() + or + pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() +} + +private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) { + lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion) + or + lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted() +} + +private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) { + ( + pointerOut instanceof PointerAddExpr + or + pointerOut instanceof PointerSubExpr + ) and + pointerIn = pointerOut.getAChild().getFullyConverted() and + pointerIn.getUnspecifiedType() instanceof PointerType + or + pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted() + or + pointerIn.getConversion() = pointerOut.(Cast) + or + pointerIn.getConversion() = pointerOut.(ParenthesisExpr) + or + pointerIn = pointerOut.(ConditionalExpr).getThen().getFullyConverted() + or + pointerIn = pointerOut.(ConditionalExpr).getElse().getFullyConverted() + or + pointerIn = pointerOut.(CommaExpr).getRightOperand().getFullyConverted() + or + pointerIn = pointerOut.(StmtExpr).getResultExpr().getFullyConverted() +} + +private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { + lvalueIn.getConversion() = referenceOut.(ReferenceToExpr) +} + +private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { + referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) +} + +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + +private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { + referenceOut = + any(FunctionCall call | + stdIdentityFunction(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) + or + referenceIn.getConversion() = referenceOut.(Cast) + or + referenceIn.getConversion() = referenceOut.(ParenthesisExpr) +} + +private predicate assignmentTo(Expr updated, ControlFlowNode node) { + updated = node.(Assignment).getLValue().getFullyConverted() + or + updated = node.(CrementOperation).getOperand().getFullyConverted() +} + +private predicate lvalueToUpdate(Expr lvalue, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof Class and + not call.getTarget().hasSpecifier("const") + ) + or + assignmentTo(outer, node) + or + exists(DotFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + lvalue = outer + or + exists(Expr lvalueMid | + lvalueToLvalueStep(lvalue, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + lvalueToPointerStep(lvalue, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or + exists(Expr referenceMid | + lvalueToReferenceStep(lvalue, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +private predicate pointerToUpdate(Expr pointer, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getAnArgument().getFullyConverted() and + exists(PointerType pt | pt = outer.getType().stripTopLevelSpecifiers() | + not pt.getBaseType().isConst() + ) + or + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof PointerType and + not call.getTarget().hasSpecifier("const") + ) + or + exists(PointerFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + pointer = outer + or + exists(Expr lvalueMid | + pointerToLvalueStep(pointer, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + pointerToPointerStep(pointer, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) +} + +private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode node) { + exists(Call call | + node = call and + outer = call.getAnArgument().getFullyConverted() and + not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) and + exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() | + not rt.getBaseType().isConst() + ) + ) and + reference = outer + or + exists(Expr lvalueMid | + referenceToLvalueStep(reference, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + referenceToPointerStep(reference, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or + exists(Expr referenceMid | + referenceToReferenceStep(reference, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +/** + * Holds if `node` is a control-flow node that may modify `inner` (or what it + * points to) through `outer`. The two expressions may be `Conversion`s. Plain + * assignments to variables are not included in this predicate since they are + * assumed to be analyzed by SSA or similar means. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...`, `node` = `f(...)`. + * - `inner` = `a`, `outer` = `(...)`, `node` = `f(...)`. + */ +cached +predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { + ( + lvalueToUpdate(inner, outer, node) + or + pointerToUpdate(inner, outer, node) + or + referenceToUpdate(inner, outer, node) + ) and + ( + inner instanceof VariableAccess and + // Don't track non-field assignments + (assignmentTo(outer, _) implies inner instanceof FieldAccess) + or + inner instanceof ThisExpr + or + inner instanceof Call + // `inner` could also be `*` or `ReferenceDereferenceExpr`, but we + // can't do anything useful with those at the moment. + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll index 154430794d4..e57af3b8d31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -53,26 +53,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(Call call, Function f, Call ctx) { none() } +predicate mayBenefitFromCallContext(Call call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. */ -Function prunedViableImplInCallContext(Call call, Call ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, Call call) { none() } - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ -Function prunedViableImplInCallContextReverse(Call call, Call ctx) { none() } +Function viableImplInCallContext(Call call, Call ctx) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index b241a574c97..27ab1d01feb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,13 +289,94 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) + ) } /** @@ -340,21 +387,10 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,26 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -564,6 +615,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +637,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +649,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +663,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } @@ -665,9 +730,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -679,6 +741,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -689,25 +768,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 1c6ab9a8c46..42c31bca69c 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -148,12 +148,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { @@ -168,26 +162,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override Type getContainerType() { result = f.getDeclaringType() } - - override Type getType() { result = f.getType() } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } /** @@ -235,16 +217,19 @@ predicate readStep(Node node1, Content f, Node node2) { } /** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. + * Holds if values stored inside content `c` are cleared at node `n`. */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and +predicate clearsContent(Node n, Content c) { + none() // stub implementation +} + +/** Gets the type of `n` used for type pruning. */ +Type getNodeType(Node n) { + suppressUnusedNode(n) and result instanceof VoidType // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets a string representation of a type returned by `getNodeType`. */ string ppReprType(Type t) { none() } // stub implementation /** @@ -256,7 +241,7 @@ predicate compatibleTypes(Type t1, Type t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers @@ -311,9 +296,9 @@ predicate isImmutableOrUnobservable(Node n) { or dt.getBaseType() instanceof RoutineType ) - or - // Isn't something we can track - n.asExpr() instanceof Call // The above list of cases isn't exhaustive, but it narrows down the // consistency alerts enough that most of them are interesting. } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 618c29ebb86..47da6ca6e54 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -20,10 +20,12 @@ private newtype TNode = TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or TPreConstructorInitThis(ConstructorFieldInit cfi) or TPostConstructorInitThis(ConstructorFieldInit cfi) or - TThisArgumentPostUpdate(ThisExpr ta) { - exists(Call c, int i | - ta = c.getArgument(i) and - not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst() + TInnerPartialDefinitionNode(Expr e) { + exists(PartialDefinition def, Expr outer | + def.definesExpressions(e, outer) and + // This condition ensures that we don't get two post-update nodes sharing + // the same pre-update node. + e != outer ) } or TUninitializedNode(LocalVariable v) { not v.hasInitializer() } or @@ -66,7 +68,7 @@ class Node extends TNode { * a partial definition of `&x`). */ Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getPartialDefinition().getDefinedExpr() + this.(PartialDefinitionNode).getPartialDefinition().definesExpressions(_, result) } /** @@ -114,33 +116,12 @@ class ExprNode extends Node, TExprNode { override string toString() { result = expr.toString() } - override Location getLocation() { - result = getExprLocationOverride(expr) - or - not exists(getExprLocationOverride(expr)) and - result = expr.getLocation() - } + override Location getLocation() { result = expr.getLocation() } /** Gets the expression corresponding to this node. */ Expr getExpr() { result = expr } } -/** - * Gets a location for `e` that's more accurate than `e.getLocation()`, if any. - */ -private Location getExprLocationOverride(Expr e) { - // Base case: the parent has a better location than `e`. - e.getLocation() instanceof UnknownExprLocation and - result = e.getParent().getLocation() and - not result instanceof UnknownLocation - or - // Recursive case: the parent has a location override that's better than what - // `e` has. - e.getLocation() instanceof UnknownExprLocation and - result = getExprLocationOverride(e.getParent()) and - not result instanceof UnknownLocation -} - abstract class ParameterNode extends Node, TNode { /** * Holds if this node is the parameter of `c` at the specified (zero-based) @@ -198,25 +179,23 @@ class ImplicitParameterNode extends ParameterNode, TInstanceParameterNode { * returned. This node will have its `getArgument()` equal to `&x`. */ class DefinitionByReferenceNode extends PartialDefinitionNode { - VariableAccess va; + Expr inner; Expr argument; DefinitionByReferenceNode() { - exists(DefinitionByReference def | - def = this.getPartialDefinition() and - argument = def.getDefinedExpr() and - va = def.getVariableAccess() - ) + this.getPartialDefinition().(DefinitionByReference).definesExpressions(inner, argument) } - override Function getFunction() { result = va.getEnclosingFunction() } + override Function getFunction() { result = inner.getEnclosingFunction() } - override Type getType() { result = va.getType() } + override Type getType() { result = inner.getType() } override string toString() { result = "ref arg " + argument.toString() } override Location getLocation() { result = argument.getLocation() } + override ExprNode getPreUpdateNode() { result.getExpr() = argument } + /** Gets the argument corresponding to this node. */ Expr getArgument() { result = argument } @@ -297,7 +276,7 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } - override Node getPreUpdateNode() { result.asExpr() = pd.getDefinedExpr() } + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } override Location getLocation() { result = pd.getActualLocation() } @@ -306,14 +285,23 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } -private class ThisArgumentPostUpdateNode extends PostUpdateNode, TThisArgumentPostUpdate { - ThisExpr thisExpr; +/** + * A post-update node on the `e->f` in `f(&e->f)` (and other forms). + */ +private class InnerPartialDefinitionNode extends TInnerPartialDefinitionNode, PostUpdateNode { + Expr e; - ThisArgumentPostUpdateNode() { this = TThisArgumentPostUpdate(thisExpr) } + InnerPartialDefinitionNode() { this = TInnerPartialDefinitionNode(e) } - override Node getPreUpdateNode() { result.asExpr() = thisExpr } + override ExprNode getPreUpdateNode() { result.getExpr() = e } - override string toString() { result = "ref arg this" } + override Function getFunction() { result = e.getEnclosingFunction() } + + override Type getType() { result = e.getType() } + + override string toString() { result = e.toString() + " [inner post update]" } + + override Location getLocation() { result = e.getLocation() } } /** @@ -518,6 +506,14 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // post-update-`this` -> following-`this`-ref ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + // In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`, + // from which there is field flow to `x` via reverse read. + exists(PartialDefinition def, Expr inner, Expr outer | + def.definesExpressions(inner, outer) and + inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and + outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr() + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index d35bc4533b9..72033b0f72d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -5,6 +5,7 @@ import cpp private import semmle.code.cpp.controlflow.SSA private import semmle.code.cpp.dataflow.internal.SubBasicBlocks +private import semmle.code.cpp.dataflow.internal.AddressFlow /** * A conceptual variable that is assigned only once, like an SSA variable. This @@ -56,15 +57,9 @@ class FlowVar extends TFlowVar { abstract predicate definedByExpr(Expr e, ControlFlowNode node); /** - * Holds if this `FlowVar` corresponds to the data written by a call that - * passes a variable as argument `arg`. - */ - cached - abstract predicate definedByReference(Expr arg); - - /** - * Holds if this `FlowVar` is a `PartialDefinition` whose defined expression - * is `e`. + * Holds if this `FlowVar` is a `PartialDefinition` whose outer defined + * expression is `e`. For example, in `f(&x)`, the outer defined expression + * is `&x`. */ cached abstract predicate definedPartiallyAt(Expr e); @@ -113,39 +108,21 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) { - assignmentLikeOperation(node, _, fa, _) - } - class PartialDefinition extends Expr { + Expr innerDefinedExpr; ControlFlowNode node; PartialDefinition() { - exists(FieldAccess fa | this = fa.getQualifier() | - // `fa = ...`, `fa += ...`, etc. - isInstanceFieldWrite(fa, node) - or - // `fa.a = ...`, `f(&fa)`, etc. - exists(PartialDefinition pd | - node = pd.getSubBasicBlockStart() and - fa = pd.getDefinedExpr() - ) + exists(Expr convertedInner | + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + not this instanceof Conversion ) - or - // `e.f(...)` - exists(Call call | - this = call.getQualifier() and - not call.getTarget().hasSpecifier("const") - ) and - node = this - or - // `f(e)`, `f(&e)`, etc. - referenceArgument(node, this) } - predicate partiallyDefines(Variable v) { this = v.getAnAccess() } + predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() } - predicate partiallyDefinesThis(ThisExpr e) { this = e } + predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } /** * Gets the subBasicBlock where this `PartialDefinition` is defined. @@ -153,14 +130,17 @@ private module PartialDefinitions { ControlFlowNode getSubBasicBlockStart() { result = node } /** - * Gets the expression that is being partially defined. For example in the - * following code: - * ``` - * x.y = 1; - * ``` - * The expression `x` is being partially defined. + * Holds if this partial definition may modify `inner` (or what it points + * to) through `outer`. These expressions will never be `Conversion`s. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...` + * - `inner` = `a`, `outer` = `*` */ - Expr getDefinedExpr() { result = this } + predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } /** * Gets the location of this element, adjusted to avoid unknown locations @@ -180,38 +160,7 @@ private module PartialDefinitions { * A partial definition that's a definition by reference. */ class DefinitionByReference extends PartialDefinition { - VariableAccess va; - - DefinitionByReference() { referenceArgument(va, this) } - - VariableAccess getVariableAccess() { result = va } - - override predicate partiallyDefines(Variable v) { va = v.getAnAccess() } - } - - private predicate referenceArgument(VariableAccess va, Expr argument) { - argument = any(Call c).getAnArgument() and - exists(Type argumentType | - argumentType = argument.getFullyConverted().getType().stripTopLevelSpecifiers() - | - argumentType instanceof ReferenceType and - not argumentType.(ReferenceType).getBaseType().isConst() and - va = argument - or - argumentType instanceof PointerType and - not argumentType.(PointerType).getBaseType().isConst() and - ( - // f(variable) - va = argument - or - // f(&variable) - va = argument.(AddressOfExpr).getOperand() - or - // f(&array[0]) - va.getType().getUnspecifiedType() instanceof ArrayType and - va = argument.(AddressOfExpr).getOperand().(ArrayExpr).getArrayBase() - ) - ) + DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } } @@ -328,10 +277,6 @@ module FlowVar_internal { ) } - override predicate definedByReference(Expr arg) { - none() // Not supported for SSA. See `fullySupportedSsaVariable`. - } - override predicate definedPartiallyAt(Expr e) { none() } override predicate definedByInitialValue(StackVariable param) { @@ -416,19 +361,11 @@ module FlowVar_internal { node = sbb.getANode() } - override predicate definedByReference(Expr arg) { - exists(DefinitionByReference def | - def.partiallyDefines(v) and - sbb = def.getSubBasicBlockStart() and - arg = def.getDefinedExpr() - ) - } - override predicate definedPartiallyAt(Expr e) { exists(PartialDefinition p | p.partiallyDefines(v) and sbb = p.getSubBasicBlockStart() and - e = p.getDefinedExpr() + p.definesExpressions(_, e) ) } @@ -441,11 +378,6 @@ module FlowVar_internal { this.definedByInitialValue(_) and result = "initial value of " + v or - exists(Expr arg | - this.definedByReference(arg) and - result = "definition by reference of " + v - ) - or exists(Expr partialDef | this.definedPartiallyAt(partialDef) and result = "partial definition at " + partialDef @@ -454,7 +386,6 @@ module FlowVar_internal { // impossible case not this.definedByExpr(_, _) and not this.definedByInitialValue(_) and - not this.definedByReference(_) and not this.definedPartiallyAt(_) and result = "undefined " + v } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll index dafcd1fdd97..fa9d2e94081 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll @@ -168,6 +168,7 @@ class SubBasicBlock extends ControlFlowNodeBase { /** Gets the first control-flow node in this `SubBasicBlock`. */ ControlFlowNode getStart() { result = this } + /** Gets the function that contains this `SubBasicBlock`. */ pragma[noinline] Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index 86a46c2531d..681fb41fa67 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling accesses including variable accesses, enum + * constant accesses and function accesses. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Variable import semmle.code.cpp.Enum @@ -6,9 +11,13 @@ private import semmle.code.cpp.dataflow.EscapesTree /** * A C/C++ access expression. This refers to a function, variable, or enum constant. */ -abstract class Access extends Expr, NameQualifiableElement { +class Access extends Expr, NameQualifiableElement, @access { + // As `@access` is a union type containing `@routineexpr` (which describes function accesses + // that are called), we need to exclude function calls. + Access() { this instanceof @routineexpr implies not iscall(underlyingElement(this), _) } + /** Gets the accessed function, variable, or enum constant. */ - abstract Declaration getTarget(); + Declaration getTarget() { none() } // overridden in subclasses override predicate mayBeImpure() { none() } @@ -32,7 +41,7 @@ abstract class Access extends Expr, NameQualifiableElement { * ``` */ class EnumConstantAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "EnumConstantAccess" } + override string getAPrimaryQlClass() { result = "EnumConstantAccess" } EnumConstantAccess() { exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -57,7 +66,7 @@ class EnumConstantAccess extends Access, @varaccess { * ``` */ class VariableAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "VariableAccess" } + override string getAPrimaryQlClass() { result = "VariableAccess" } VariableAccess() { not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -162,7 +171,7 @@ class VariableAccess extends Access, @varaccess { * ``` */ class FieldAccess extends VariableAccess { - override string getCanonicalQLClass() { result = "FieldAccess" } + override string getAPrimaryQlClass() { result = "FieldAccess" } FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) } @@ -190,7 +199,7 @@ class FieldAccess extends VariableAccess { * ``` */ class PointerFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "PointerFieldAccess" } + override string getAPrimaryQlClass() { result = "PointerFieldAccess" } PointerFieldAccess() { exists(PointerType t | @@ -207,7 +216,7 @@ class PointerFieldAccess extends FieldAccess { * distinguish whether or not the type of `obj` is a reference type. */ class DotFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "DotFieldAccess" } + override string getAPrimaryQlClass() { result = "DotFieldAccess" } DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) } } @@ -228,7 +237,7 @@ class DotFieldAccess extends FieldAccess { * ``` */ class ReferenceFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ReferenceFieldAccess" } + override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" } ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) } } @@ -249,7 +258,7 @@ class ReferenceFieldAccess extends DotFieldAccess { * ``` */ class ValueFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ValueFieldAccess" } + override string getAPrimaryQlClass() { result = "ValueFieldAccess" } ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) } } @@ -303,7 +312,7 @@ private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.get * `ImplicitThisFieldAccess`. */ class ImplicitThisFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "ImplicitThisFieldAccess" } + override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" } ImplicitThisFieldAccess() { not exists(this.getQualifier()) } } @@ -328,7 +337,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { override predicate isConstant() { any() } - override string getCanonicalQLClass() { result = "PointerToFieldLiteral" } + override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" } } /** @@ -345,7 +354,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { class FunctionAccess extends Access, @routineexpr { FunctionAccess() { not iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionAccess" } + override string getAPrimaryQlClass() { result = "FunctionAccess" } /** Gets the accessed function. */ override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) } @@ -395,7 +404,7 @@ class ParamAccessForType extends Expr, @param_ref { * ``` */ class TypeName extends Expr, @type_operand { - override string getCanonicalQLClass() { result = "TypeName" } + override string getAPrimaryQlClass() { result = "TypeName" } override string toString() { result = this.getType().getName() } } @@ -414,7 +423,7 @@ class TypeName extends Expr, @type_operand { * `OverloadedArrayExpr`. */ class ArrayExpr extends Expr, @subscriptexpr { - override string getCanonicalQLClass() { result = "ArrayExpr" } + override string getAPrimaryQlClass() { result = "ArrayExpr" } /** * Gets the array or pointer expression being subscripted. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 278db89b41e..b94c9cee724 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling arithmetic operations such as `+`, `-`, `*` + * and `++`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { } class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "UnaryMinusExpr" } + override string getAPrimaryQlClass() { result = "UnaryMinusExpr" } override int getPrecedence() { result = 16 } } @@ -28,7 +33,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "UnaryPlusExpr" } + override string getAPrimaryQlClass() { result = "UnaryPlusExpr" } override int getPrecedence() { result = 16 } } @@ -45,7 +50,7 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { class ConjugationExpr extends UnaryArithmeticOperation, @conjugation { override string getOperator() { result = "~" } - override string getCanonicalQLClass() { result = "ConjugationExpr" } + override string getAPrimaryQlClass() { result = "ConjugationExpr" } } /** @@ -107,7 +112,7 @@ class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr { class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PrefixIncrExpr" } + override string getAPrimaryQlClass() { result = "PrefixIncrExpr" } override int getPrecedence() { result = 16 } } @@ -123,7 +128,7 @@ class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preinc class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PrefixDecrExpr" } + override string getAPrimaryQlClass() { result = "PrefixDecrExpr" } override int getPrecedence() { result = 16 } } @@ -139,7 +144,7 @@ class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predec class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PostfixIncrExpr" } + override string getAPrimaryQlClass() { result = "PostfixIncrExpr" } override int getPrecedence() { result = 17 } @@ -157,7 +162,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PostfixDecrExpr" } + override string getAPrimaryQlClass() { result = "PostfixDecrExpr" } override int getPrecedence() { result = 17 } @@ -175,7 +180,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { override string getOperator() { result = "__real" } - override string getCanonicalQLClass() { result = "RealPartExpr" } + override string getAPrimaryQlClass() { result = "RealPartExpr" } } /** @@ -189,7 +194,7 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr { override string getOperator() { result = "__imag" } - override string getCanonicalQLClass() { result = "ImaginaryPartExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" } } /** @@ -208,7 +213,7 @@ class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { } class AddExpr extends BinaryArithmeticOperation, @addexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "AddExpr" } + override string getAPrimaryQlClass() { result = "AddExpr" } override int getPrecedence() { result = 13 } } @@ -222,7 +227,7 @@ class AddExpr extends BinaryArithmeticOperation, @addexpr { class SubExpr extends BinaryArithmeticOperation, @subexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "SubExpr" } + override string getAPrimaryQlClass() { result = "SubExpr" } override int getPrecedence() { result = 13 } } @@ -236,7 +241,7 @@ class SubExpr extends BinaryArithmeticOperation, @subexpr { class MulExpr extends BinaryArithmeticOperation, @mulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "MulExpr" } + override string getAPrimaryQlClass() { result = "MulExpr" } override int getPrecedence() { result = 14 } } @@ -250,7 +255,7 @@ class MulExpr extends BinaryArithmeticOperation, @mulexpr { class DivExpr extends BinaryArithmeticOperation, @divexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "DivExpr" } + override string getAPrimaryQlClass() { result = "DivExpr" } override int getPrecedence() { result = 14 } } @@ -264,7 +269,7 @@ class DivExpr extends BinaryArithmeticOperation, @divexpr { class RemExpr extends BinaryArithmeticOperation, @remexpr { override string getOperator() { result = "%" } - override string getCanonicalQLClass() { result = "RemExpr" } + override string getAPrimaryQlClass() { result = "RemExpr" } override int getPrecedence() { result = 14 } } @@ -281,7 +286,7 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr { class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "ImaginaryMulExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" } override int getPrecedence() { result = 14 } } @@ -298,7 +303,7 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "ImaginaryDivExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" } override int getPrecedence() { result = 14 } } @@ -316,7 +321,7 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" } + override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" } override int getPrecedence() { result = 13 } } @@ -334,7 +339,7 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" } override int getPrecedence() { result = 13 } } @@ -352,7 +357,7 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "RealImaginarySubExpr" } + override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" } override int getPrecedence() { result = 13 } } @@ -370,7 +375,7 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" } override int getPrecedence() { result = 13 } } @@ -384,7 +389,7 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { class MinExpr extends BinaryArithmeticOperation, @minexpr { override string getOperator() { result = "?" } - override string getCanonicalQLClass() { result = "MaxExpr" } + override string getAPrimaryQlClass() { result = "MaxExpr" } } /** @@ -414,7 +419,7 @@ class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "PointerAddExpr" } + override string getAPrimaryQlClass() { result = "PointerAddExpr" } override int getPrecedence() { result = 13 } } @@ -429,7 +434,7 @@ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerSubExpr" } + override string getAPrimaryQlClass() { result = "PointerSubExpr" } override int getPrecedence() { result = 13 } } @@ -444,7 +449,7 @@ class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerDiffExpr" } + override string getAPrimaryQlClass() { result = "PointerDiffExpr" } override int getPrecedence() { result = 13 } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll index 4d2f61f1b6d..0c56d9a4d51 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll @@ -38,7 +38,7 @@ class Assignment extends Operation, @assign_expr { class AssignExpr extends Assignment, @assignexpr { override string getOperator() { result = "=" } - override string getCanonicalQLClass() { result = "AssignExpr" } + override string getAPrimaryQlClass() { result = "AssignExpr" } /** Gets a textual representation of this assignment. */ override string toString() { result = "... = ..." } @@ -64,7 +64,7 @@ class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { } * ``` */ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { - override string getCanonicalQLClass() { result = "AssignAddExpr" } + override string getAPrimaryQlClass() { result = "AssignAddExpr" } override string getOperator() { result = "+=" } } @@ -76,7 +76,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { * ``` */ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { - override string getCanonicalQLClass() { result = "AssignSubExpr" } + override string getAPrimaryQlClass() { result = "AssignSubExpr" } override string getOperator() { result = "-=" } } @@ -88,7 +88,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { * ``` */ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { - override string getCanonicalQLClass() { result = "AssignMulExpr" } + override string getAPrimaryQlClass() { result = "AssignMulExpr" } override string getOperator() { result = "*=" } } @@ -100,7 +100,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { * ``` */ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { - override string getCanonicalQLClass() { result = "AssignDivExpr" } + override string getAPrimaryQlClass() { result = "AssignDivExpr" } override string getOperator() { result = "/=" } } @@ -112,7 +112,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { * ``` */ class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr { - override string getCanonicalQLClass() { result = "AssignRemExpr" } + override string getAPrimaryQlClass() { result = "AssignRemExpr" } override string getOperator() { result = "%=" } } @@ -130,7 +130,7 @@ class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { } * ``` */ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { - override string getCanonicalQLClass() { result = "AssignAndExpr" } + override string getAPrimaryQlClass() { result = "AssignAndExpr" } override string getOperator() { result = "&=" } } @@ -142,7 +142,7 @@ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { * ``` */ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { - override string getCanonicalQLClass() { result = "AssignOrExpr" } + override string getAPrimaryQlClass() { result = "AssignOrExpr" } override string getOperator() { result = "|=" } } @@ -154,7 +154,7 @@ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { * ``` */ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { - override string getCanonicalQLClass() { result = "AssignXorExpr" } + override string getAPrimaryQlClass() { result = "AssignXorExpr" } override string getOperator() { result = "^=" } } @@ -166,7 +166,7 @@ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { * ``` */ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { - override string getCanonicalQLClass() { result = "AssignLShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignLShiftExpr" } override string getOperator() { result = "<<=" } } @@ -178,7 +178,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { * ``` */ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { - override string getCanonicalQLClass() { result = "AssignRShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignRShiftExpr" } override string getOperator() { result = ">>=" } } @@ -190,7 +190,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { * ``` */ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { - override string getCanonicalQLClass() { result = "AssignPointerAddExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" } override string getOperator() { result = "+=" } } @@ -202,7 +202,7 @@ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { * ``` */ class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr { - override string getCanonicalQLClass() { result = "AssignPointerSubExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" } override string getOperator() { result = "-=" } } @@ -227,7 +227,7 @@ class ConditionDeclExpr extends Expr, @condition_decl { */ deprecated Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ConditionDeclExpr" } + override string getAPrimaryQlClass() { result = "ConditionDeclExpr" } /** * Gets the compiler-generated variable access that conceptually occurs after diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll index 2d0b6cda0d6..3a4f14d9ab8 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and + * `|`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -16,7 +21,7 @@ class ComplementExpr extends UnaryBitwiseOperation, @complementexpr { override int getPrecedence() { result = 16 } - override string getCanonicalQLClass() { result = "ComplementExpr" } + override string getAPrimaryQlClass() { result = "ComplementExpr" } } /** @@ -35,7 +40,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "LShiftExpr" } + override string getAPrimaryQlClass() { result = "LShiftExpr" } } /** @@ -49,7 +54,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "RShiftExpr" } + override string getAPrimaryQlClass() { result = "RShiftExpr" } } /** @@ -63,7 +68,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr { override int getPrecedence() { result = 8 } - override string getCanonicalQLClass() { result = "BitwiseAndExpr" } + override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } /** @@ -77,7 +82,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr { override int getPrecedence() { result = 6 } - override string getCanonicalQLClass() { result = "BitwiseOrExpr" } + override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } /** @@ -91,5 +96,5 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr { override int getPrecedence() { result = 7 } - override string getCanonicalQLClass() { result = "BitwiseXorExpr" } + override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 446bdbdee51..3c627d712b4 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -1,28 +1,23 @@ +/** + * Provides classes for modeling built-in operations. Built-in operations are + * typically compiler specific and are used by libraries and generated code. + */ + import semmle.code.cpp.exprs.Expr /** - * A C/C++ builtin operation. This is the root QL class encompassing + * A C/C++ built-in operation. This is the root QL class encompassing * built-in functionality. */ -abstract class BuiltInOperation extends Expr { - override string getCanonicalQLClass() { result = "BuiltInOperation" } +class BuiltInOperation extends Expr, @builtin_op { + override string getAPrimaryQlClass() { result = "BuiltInOperation" } } /** * A C/C++ built-in operation that is used to support functions with variable numbers of arguments. * This includes `va_start`, `va_end`, `va_copy`, and `va_arg`. */ -class VarArgsExpr extends BuiltInOperation { - VarArgsExpr() { - this instanceof BuiltInVarArgsStart - or - this instanceof BuiltInVarArgsEnd - or - this instanceof BuiltInVarArg - or - this instanceof BuiltInVarArgCopy - } -} +class VarArgsExpr extends BuiltInOperation, @var_args_expr { } /** * A C/C++ `__builtin_va_start` built-in operation (used by some @@ -35,7 +30,7 @@ class VarArgsExpr extends BuiltInOperation { class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { override string toString() { result = "__builtin_va_start" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsStart" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" } /** * Gets the `va_list` argument. @@ -60,7 +55,7 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { override string toString() { result = "__builtin_va_end" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsEnd" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" } /** * Gets the `va_list` argument. @@ -78,7 +73,7 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { class BuiltInVarArg extends BuiltInOperation, @vaargexpr { override string toString() { result = "__builtin_va_arg" } - override string getCanonicalQLClass() { result = "BuiltInVarArg" } + override string getAPrimaryQlClass() { result = "BuiltInVarArg" } /** * Gets the `va_list` argument. @@ -98,7 +93,7 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr { class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { override string toString() { result = "__builtin_va_copy" } - override string getCanonicalQLClass() { result = "BuiltInVarArgCopy" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" } /** * Gets the destination `va_list` argument. @@ -120,7 +115,7 @@ class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { class BuiltInNoOp extends BuiltInOperation, @noopexpr { override string toString() { result = "__noop" } - override string getCanonicalQLClass() { result = "BuiltInNoOp" } + override string getAPrimaryQlClass() { result = "BuiltInNoOp" } } /** @@ -142,7 +137,7 @@ deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf; class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { override string toString() { result = "__builtin_offsetof" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInOffsetOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" } } /** @@ -159,7 +154,7 @@ class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { override string toString() { result = "__INTADDR__" } - override string getCanonicalQLClass() { result = "BuiltInIntAddr" } + override string getAPrimaryQlClass() { result = "BuiltInIntAddr" } } /** @@ -174,7 +169,7 @@ class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { override string toString() { result = "__has_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" } } /** @@ -189,7 +184,7 @@ class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { override string toString() { result = "__has_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" } } /** @@ -205,7 +200,7 @@ class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign { override string toString() { result = "__has_nothrow_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" } } /** @@ -221,7 +216,7 @@ class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassi class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr { override string toString() { result = "__has_nothrow_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" } } /** @@ -236,7 +231,7 @@ class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothro class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { override string toString() { result = "__has_nothrow_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" } } /** @@ -252,7 +247,7 @@ class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign { override string toString() { result = "__has_trivial_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" } } /** @@ -267,7 +262,7 @@ class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassi class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr { override string toString() { result = "__has_trivial_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" } } /** @@ -282,7 +277,7 @@ class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivia class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { override string toString() { result = "__has_trivial_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" } } /** @@ -297,7 +292,7 @@ class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor { override string toString() { result = "__has_trivial_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" } } /** @@ -312,7 +307,7 @@ class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivial class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr { override string toString() { result = "__has_user_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasUserDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" } } /** @@ -330,7 +325,7 @@ class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr { override string toString() { result = "__has_virtual_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasVirtualDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" } } /** @@ -345,7 +340,7 @@ class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtual class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { override string toString() { result = "__is_abstract" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsAbstract" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" } } /** @@ -360,7 +355,7 @@ class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { override string toString() { result = "__is_base_of" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsBaseOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" } } /** @@ -375,7 +370,7 @@ class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { override string toString() { result = "__is_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" } } /** @@ -390,7 +385,7 @@ class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { override string toString() { result = "__is_convertible_to" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConvertibleTo" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" } } /** @@ -405,7 +400,7 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { override string toString() { result = "__is_empty" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEmpty" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" } } /** @@ -420,7 +415,7 @@ class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { override string toString() { result = "__is_enum" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEnum" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" } } /** @@ -437,7 +432,7 @@ class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { override string toString() { result = "__is_pod" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPod" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" } } /** @@ -452,7 +447,7 @@ class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { override string toString() { result = "__is_polymorphic" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPolymorphic" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" } } /** @@ -467,7 +462,7 @@ class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr { override string toString() { result = "__is_union" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsUnion" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" } } /** @@ -506,7 +501,7 @@ class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typesco class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector { override string toString() { result = "__builtin_shufflevector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInShuffleVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" } } /** @@ -526,7 +521,7 @@ class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshu class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector { override string toString() { result = "__builtin_convertvector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInConvertVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" } } /** @@ -548,7 +543,7 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation, result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget() } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInAddressOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" } override string getOperator() { result = "__builtin_addressof" } } @@ -570,7 +565,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, @istriviallyconstructibleexpr { override string toString() { result = "__is_trivially_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" } } /** @@ -587,7 +582,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr { override string toString() { result = "__is_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" } } /** @@ -604,7 +599,7 @@ class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleex class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr { override string toString() { result = "__is_nothrow_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" } } /** @@ -620,7 +615,7 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr { override string toString() { result = "__is_trivially_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" } } /** @@ -639,7 +634,7 @@ class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istrivi class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr { override string toString() { result = "__is_trivially_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" } } /** @@ -655,7 +650,7 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr { override string toString() { result = "__is_nothrow_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" } } /** @@ -675,7 +670,7 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr { override string toString() { result = "__is_standard_layout" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsStandardLayout" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" } } /** @@ -689,7 +684,7 @@ class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayo class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr { override string toString() { result = "__is_trivially_copyable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyCopyable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" } } /** @@ -709,7 +704,7 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr { override string toString() { result = "__is_literal_type" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsLiteralType" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" } } /** @@ -727,7 +722,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, @hastrivialmoveconstructorexpr { override string toString() { result = "__has_trivial_move_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } } /** @@ -745,7 +740,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr { override string toString() { result = "__has_trivial_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" } } /** @@ -761,7 +756,7 @@ class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivial class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr { override string toString() { result = "__has_nothrow_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNothrowMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" } } /** @@ -780,7 +775,7 @@ class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrow class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr { override string toString() { result = "__is_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" } } /** @@ -796,7 +791,7 @@ class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructible class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr { override string toString() { result = "__is_nothrow_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" } } /** @@ -811,7 +806,7 @@ class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothro class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { override string toString() { result = "__has_finalizer" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasFinalizer" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" } } /** @@ -825,7 +820,7 @@ class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { override string toString() { result = "__is_delegate" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDelegate" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" } } /** @@ -838,7 +833,7 @@ class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr { override string toString() { result = "__is_interface_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsInterfaceClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" } } /** @@ -855,7 +850,7 @@ class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfacecla class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { override string toString() { result = "__is_ref_array" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefArray" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" } } /** @@ -872,7 +867,7 @@ class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { override string toString() { result = "__is_ref_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" } } /** @@ -890,7 +885,7 @@ class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { override string toString() { result = "__is_sealed" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSealed" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" } } /** @@ -909,7 +904,7 @@ class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr { override string toString() { result = "__is_simple_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSimpleValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" } } /** @@ -926,7 +921,7 @@ class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalu class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { override string toString() { result = "__is_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" } } /** @@ -944,7 +939,7 @@ class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { override string toString() { result = "__is_final" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsFinal" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" } } /** @@ -959,7 +954,7 @@ class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { override string toString() { result = "__builtin_choose_expr" } - override string getCanonicalQLClass() { result = "BuiltInChooseExpr" } + override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" } } /** @@ -976,7 +971,7 @@ class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { class VectorFillOperation extends UnaryOperation, @vec_fill { override string getOperator() { result = "(vector fill)" } - override string getCanonicalQLClass() { result = "VectorFillOperation" } + override string getAPrimaryQlClass() { result = "VectorFillOperation" } } /** @@ -985,7 +980,7 @@ class VectorFillOperation extends UnaryOperation, @vec_fill { class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex { override string toString() { result = "__builtin_complex" } - override string getCanonicalQLClass() { result = "BuiltInComplexOperation" } + override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" } /** Gets the operand corresponding to the real part of the complex number. */ Expr getRealOperand() { this.hasChild(result, 0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index d22e090a9e6..2f1c29be8bc 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -1,13 +1,29 @@ +/** + * Provides classes for modeling call expressions including direct calls to + * functions, constructor and destructor calls, and calls made through function + * pointers. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Function private import semmle.code.cpp.dataflow.EscapesTree +private class TCall = @funbindexpr or @callexpr; + /** * A C/C++ call. - * - * This is the abstract root QL class for all types of calls. */ -abstract class Call extends Expr, NameQualifiableElement { +class Call extends Expr, NameQualifiableElement, TCall { + // `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes + // `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to + // that function. That's why the charpred for `FunctionCall` requires: + // ``` + // iscall(underlyingElement(this), _) + // ``` + // So for the charpred for `Call` we include the requirement that if this is an instance of + // `@funbindexpr` it must be a _call_ to the function. + Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) } + /** * Gets the number of arguments (actual parameters) of this call. The count * does _not_ include the qualifier of the call, if any. @@ -74,7 +90,7 @@ abstract class Call extends Expr, NameQualifiableElement { * method, and it might not exist. * - For a variable call, it never exists. */ - abstract Function getTarget(); + Function getTarget() { none() } // overridden in subclasses override int getPrecedence() { result = 17 } @@ -82,7 +98,8 @@ abstract class Call extends Expr, NameQualifiableElement { /** * Holds if this call passes the variable accessed by `va` by - * reference as the `i`th argument. + * reference as the `i`th argument. The qualifier of a call to a member + * function is `i = -1`. * * A variable is passed by reference if the `i`th parameter of the function * receives an address that points within the object denoted by `va`. For a @@ -101,11 +118,15 @@ abstract class Call extends Expr, NameQualifiableElement { */ predicate passesByReference(int i, VariableAccess va) { variableAddressEscapesTree(va, this.getArgument(i).getFullyConverted()) + or + variableAddressEscapesTree(va, this.getQualifier().getFullyConverted()) and + i = -1 } /** * Holds if this call passes the variable accessed by `va` by - * reference to non-const data as the `i`th argument. + * reference to non-const data as the `i`th argument. The qualifier of a + * call to a member function is `i = -1`. * * A variable is passed by reference if the `i`th parameter of the function * receives an address that points within the object denoted by `va`. For a @@ -124,6 +145,9 @@ abstract class Call extends Expr, NameQualifiableElement { */ predicate passesByReferenceNonConst(int i, VariableAccess va) { variableAddressEscapesTreeNonConst(va, this.getArgument(i).getFullyConverted()) + or + variableAddressEscapesTreeNonConst(va, this.getQualifier().getFullyConverted()) and + i = -1 } } @@ -140,7 +164,7 @@ abstract class Call extends Expr, NameQualifiableElement { class FunctionCall extends Call, @funbindexpr { FunctionCall() { iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionCall" } + override string getAPrimaryQlClass() { result = "FunctionCall" } /** Gets an explicit template argument for this call. */ Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) } @@ -289,7 +313,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { getTarget().getEffectiveNumberOfParameters() = 1 } - override string getCanonicalQLClass() { result = "OverloadedPointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" } /** * Gets the expression this operator * applies to. @@ -337,7 +361,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { class OverloadedArrayExpr extends FunctionCall { OverloadedArrayExpr() { getTarget().hasName("operator[]") } - override string getCanonicalQLClass() { result = "OverloadedArrayExpr" } + override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" } /** * Gets the expression being subscripted. @@ -369,7 +393,7 @@ class ExprCall extends Call, @callexpr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ExprCall" } + override string getAPrimaryQlClass() { result = "ExprCall" } override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) } @@ -393,7 +417,7 @@ class ExprCall extends Call, @callexpr { class VariableCall extends ExprCall { VariableCall() { this.getExpr() instanceof VariableAccess } - override string getCanonicalQLClass() { result = "VariableCall" } + override string getAPrimaryQlClass() { result = "VariableCall" } /** * Gets the variable which yields the function pointer to call. @@ -411,7 +435,7 @@ class VariableCall extends ExprCall { class ConstructorCall extends FunctionCall { ConstructorCall() { super.getTarget() instanceof Constructor } - override string getCanonicalQLClass() { result = "ConstructorCall" } + override string getAPrimaryQlClass() { result = "ConstructorCall" } /** Gets the constructor being called. */ override Constructor getTarget() { result = super.getTarget() } @@ -430,7 +454,7 @@ class ThrowExpr extends Expr, @throw_expr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ThrowExpr" } + override string getAPrimaryQlClass() { result = "ThrowExpr" } override string toString() { result = "throw ..." } @@ -446,7 +470,7 @@ class ThrowExpr extends Expr, @throw_expr { class ReThrowExpr extends ThrowExpr { ReThrowExpr() { this.getType() instanceof VoidType } - override string getCanonicalQLClass() { result = "ReThrowExpr" } + override string getAPrimaryQlClass() { result = "ReThrowExpr" } override string toString() { result = "re-throw exception " } } @@ -461,7 +485,7 @@ class ReThrowExpr extends ThrowExpr { class DestructorCall extends FunctionCall { DestructorCall() { super.getTarget() instanceof Destructor } - override string getCanonicalQLClass() { result = "DestructorCall" } + override string getAPrimaryQlClass() { result = "DestructorCall" } /** Gets the destructor being called. */ override Destructor getTarget() { result = super.getTarget() } @@ -485,7 +509,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { */ Expr getQualifier() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "VacuousDestructorCall" } + override string getAPrimaryQlClass() { result = "VacuousDestructorCall" } override string toString() { result = "(vacuous destructor call)" } } @@ -498,7 +522,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { * initializations. */ class ConstructorInit extends Expr, @ctorinit { - override string getCanonicalQLClass() { result = "ConstructorInit" } + override string getAPrimaryQlClass() { result = "ConstructorInit" } } /** @@ -506,7 +530,7 @@ class ConstructorInit extends Expr, @ctorinit { * initializer list or compiler-generated actions. */ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { - override string getCanonicalQLClass() { result = "ConstructorBaseInit" } + override string getAPrimaryQlClass() { result = "ConstructorBaseInit" } } /** @@ -523,7 +547,7 @@ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { * ``` */ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { - override string getCanonicalQLClass() { result = "ConstructorDirectInit" } + override string getAPrimaryQlClass() { result = "ConstructorDirectInit" } } /** @@ -543,7 +567,7 @@ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { * ``` */ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { - override string getCanonicalQLClass() { result = "ConstructorVirtualInit" } + override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" } } /** @@ -558,7 +582,7 @@ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { * ``` */ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit { - override string getCanonicalQLClass() { result = "ConstructorDelegationInit" } + override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" } } /** @@ -577,7 +601,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { /** Gets the field being initialized. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConstructorFieldInit" } + override string getAPrimaryQlClass() { result = "ConstructorFieldInit" } /** * Gets the expression to which the field is initialized. @@ -599,7 +623,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { * compiler-generated actions. */ class DestructorDestruction extends Expr, @dtordestruct { - override string getCanonicalQLClass() { result = "DestructorDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDestruction" } } /** @@ -607,7 +631,7 @@ class DestructorDestruction extends Expr, @dtordestruct { * compiler-generated actions. */ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { - override string getCanonicalQLClass() { result = "DestructorBaseDestruction" } + override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" } } /** @@ -621,7 +645,7 @@ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { * ``` */ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct { - override string getCanonicalQLClass() { result = "DestructorDirectDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" } } /** @@ -638,7 +662,7 @@ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirect * ``` */ class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct { - override string getCanonicalQLClass() { result = "DestructorVirtualDestruction" } + override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" } } /** @@ -656,7 +680,7 @@ class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestru /** Gets the field being destructed. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "DestructorFieldDestruction" } + override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" } /** Gets the compiler-generated call to the variable's destructor. */ DestructorCall getExpr() { result = this.getChild(0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 3a45d8597d5..e06ed095d40 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling C/C++ casts and conversions, as well as some + * type-related operators such as `sizeof` and `alignof`. + */ + import semmle.code.cpp.exprs.Expr private import semmle.code.cpp.internal.ResolveClass @@ -7,7 +12,7 @@ private import semmle.code.cpp.internal.ResolveClass * Instances of this class are not present in the main AST which is navigated by parent/child links. Instead, * instances of this class are attached to nodes in the main AST via special conversion links. */ -abstract class Conversion extends Expr { +class Conversion extends Expr, @conversion { /** Gets the expression being converted. */ Expr getExpr() { result.getConversion() = this } @@ -34,10 +39,10 @@ abstract class Conversion extends Expr { * a `PointerBaseClassConversion`, or some other semantic conversion. Similarly, * a `PointerDerivedClassConversion` may also be a `CStyleCast` or a `StaticCast`. * - * This is an abstract root QL class representing the different casts. For + * This is a root QL class representing the different casts. For * specific examples, consult the documentation for any of QL classes mentioned above. */ -abstract class Cast extends Conversion, @cast { +class Cast extends Conversion, @cast { /** * Gets a string describing the semantic conversion operation being performed by * this cast. @@ -48,10 +53,13 @@ abstract class Cast extends Conversion, @cast { /** * INTERNAL: Do not use. * Query predicates used to check invariants that should hold for all `Cast` - * nodes. To run all sanity queries for the ASTs, including the ones below, - * run "semmle/code/cpp/ASTSanity.ql". + * nodes. To run all consistency queries for the ASTs, including the ones below, + * run "semmle/code/cpp/ASTConsistency.ql". */ -module CastSanity { +module CastConsistency { + /** + * Holds if the cast has more than one result for `Cast.getSemanticConversionString()`. + */ query predicate multipleSemanticConversionStrings(Cast cast, Type fromType, string kind) { // Every cast should have exactly one semantic conversion kind count(cast.getSemanticConversionString()) > 1 and @@ -59,12 +67,19 @@ module CastSanity { fromType = cast.getExpr().getUnspecifiedType() } + /** + * Holds if the cast has no result for `Cast.getSemanticConversionString()`. + */ query predicate missingSemanticConversionString(Cast cast, Type fromType) { // Every cast should have exactly one semantic conversion kind not exists(cast.getSemanticConversionString()) and fromType = cast.getExpr().getUnspecifiedType() } + /** + * Holds if the cast has a result for `Cast.getSemanticConversionString()` that indicates that the + * kind of its semantic conversion is not known. + */ query predicate unknownSemanticConversionString(Cast cast, Type fromType) { // Every cast should have a known semantic conversion kind cast.getSemanticConversionString() = "unknown conversion" and @@ -82,7 +97,7 @@ module CastSanity { class CStyleCast extends Cast, @c_style_cast { override string toString() { result = "(" + this.getType().getName() + ")..." } - override string getCanonicalQLClass() { result = "CStyleCast" } + override string getAPrimaryQlClass() { result = "CStyleCast" } override int getPrecedence() { result = 16 } } @@ -101,7 +116,7 @@ class CStyleCast extends Cast, @c_style_cast { class StaticCast extends Cast, @static_cast { override string toString() { result = "static_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "StaticCast" } + override string getAPrimaryQlClass() { result = "StaticCast" } override int getPrecedence() { result = 17 } } @@ -119,7 +134,7 @@ class StaticCast extends Cast, @static_cast { class ConstCast extends Cast, @const_cast { override string toString() { result = "const_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ConstCast" } + override string getAPrimaryQlClass() { result = "ConstCast" } override int getPrecedence() { result = 17 } } @@ -137,7 +152,7 @@ class ConstCast extends Cast, @const_cast { class ReinterpretCast extends Cast, @reinterpret_cast { override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ReinterpretCast" } + override string getAPrimaryQlClass() { result = "ReinterpretCast" } override int getPrecedence() { result = 17 } } @@ -193,7 +208,7 @@ class IntegralConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralConversion" } @@ -213,7 +228,7 @@ class FloatingPointConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointConversion" } @@ -233,7 +248,7 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion" } @@ -253,7 +268,7 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion" } @@ -279,9 +294,7 @@ class PointerConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { - not exists(qlCast(this)) and result = "PointerConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } override string getSemanticConversionString() { result = "pointer conversion" } } @@ -315,7 +328,7 @@ class PointerToMemberConversion extends Cast { ) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberConversion" } @@ -336,7 +349,7 @@ class PointerToIntegralConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToIntegralConversion" } @@ -357,7 +370,7 @@ class IntegralToPointerConversion extends Cast { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToPointerConversion" } @@ -375,7 +388,7 @@ class IntegralToPointerConversion extends Cast { class BoolConversion extends Cast { BoolConversion() { conversionkinds(underlyingElement(this), 1) } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "BoolConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" } override string getSemanticConversionString() { result = "conversion to bool" } } @@ -393,7 +406,7 @@ class VoidConversion extends Cast { getUnspecifiedType() instanceof VoidType } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "VoidConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" } override string getSemanticConversionString() { result = "conversion to void" } } @@ -469,7 +482,7 @@ private Class getConversionClass(Expr expr) { class BaseClassConversion extends InheritanceConversion { BaseClassConversion() { conversionkinds(underlyingElement(this), 2) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BaseClassConversion" } @@ -496,7 +509,7 @@ class BaseClassConversion extends InheritanceConversion { class DerivedClassConversion extends InheritanceConversion { DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "DerivedClassConversion" } @@ -518,7 +531,7 @@ class DerivedClassConversion extends InheritanceConversion { class PointerToMemberBaseClassConversion extends Cast { PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion" } @@ -538,7 +551,7 @@ class PointerToMemberBaseClassConversion extends Cast { class PointerToMemberDerivedClassConversion extends Cast { PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion" } @@ -559,9 +572,7 @@ class PointerToMemberDerivedClassConversion extends Cast { class GlvalueConversion extends Cast { GlvalueConversion() { conversionkinds(underlyingElement(this), 6) } - override string getCanonicalQLClass() { - not exists(qlCast(this)) and result = "GlvalueConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" } override string getSemanticConversionString() { result = "glvalue conversion" } } @@ -587,7 +598,7 @@ class GlvalueConversion extends Cast { class PrvalueAdjustmentConversion extends Cast { PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion" } @@ -610,7 +621,7 @@ class DynamicCast extends Cast, @dynamic_cast { override int getPrecedence() { result = 17 } - override string getCanonicalQLClass() { result = "DynamicCast" } + override string getAPrimaryQlClass() { result = "DynamicCast" } override string getSemanticConversionString() { result = "dynamic_cast" } } @@ -650,6 +661,9 @@ class UuidofOperator extends Expr, @uuidof { * ``` */ class TypeidOperator extends Expr, @type_id { + /** + * Gets the type that is returned by this typeid expression. + */ Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) } /** @@ -659,7 +673,7 @@ class TypeidOperator extends Expr, @type_id { */ deprecated Type getSpecifiedType() { result = this.getResultType() } - override string getCanonicalQLClass() { result = "TypeidOperator" } + override string getAPrimaryQlClass() { result = "TypeidOperator" } /** * Gets the contained expression, if any (if this typeid contains @@ -689,7 +703,7 @@ class TypeidOperator extends Expr, @type_id { class SizeofPackOperator extends Expr, @sizeof_pack { override string toString() { result = "sizeof...(...)" } - override string getCanonicalQLClass() { result = "SizeofPackOperator" } + override string getAPrimaryQlClass() { result = "SizeofPackOperator" } override predicate mayBeImpure() { none() } @@ -699,7 +713,7 @@ class SizeofPackOperator extends Expr, @sizeof_pack { /** * A C/C++ sizeof expression. */ -abstract class SizeofOperator extends Expr, @runtime_sizeof { +class SizeofOperator extends Expr, @runtime_sizeof { override int getPrecedence() { result = 16 } } @@ -712,7 +726,7 @@ abstract class SizeofOperator extends Expr, @runtime_sizeof { class SizeofExprOperator extends SizeofOperator { SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) } - override string getCanonicalQLClass() { result = "SizeofExprOperator" } + override string getAPrimaryQlClass() { result = "SizeofExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } @@ -740,7 +754,7 @@ class SizeofExprOperator extends SizeofOperator { class SizeofTypeOperator extends SizeofOperator { SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "SizeofTypeOperator" } + override string getAPrimaryQlClass() { result = "SizeofTypeOperator" } /** Gets the contained type. */ Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } @@ -762,7 +776,7 @@ class SizeofTypeOperator extends SizeofOperator { /** * A C++11 `alignof` expression. */ -abstract class AlignofOperator extends Expr, @runtime_alignof { +class AlignofOperator extends Expr, @runtime_alignof { override int getPrecedence() { result = 16 } } @@ -819,7 +833,7 @@ class ArrayToPointerConversion extends Conversion, @array_to_pointer { /** Gets a textual representation of this conversion. */ override string toString() { result = "array to pointer conversion" } - override string getCanonicalQLClass() { result = "ArrayToPointerConversion" } + override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" } override predicate mayBeImpure() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll index a0688890a23..0c84e07f553 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling comparisons such as `==`, `!=` and `<`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -21,7 +25,7 @@ class EqualityOperation extends ComparisonOperation, @eq_op_expr { * ``` */ class EQExpr extends EqualityOperation, @eqexpr { - override string getCanonicalQLClass() { result = "EQExpr" } + override string getAPrimaryQlClass() { result = "EQExpr" } override string getOperator() { result = "==" } } @@ -33,7 +37,7 @@ class EQExpr extends EqualityOperation, @eqexpr { * ``` */ class NEExpr extends EqualityOperation, @neexpr { - override string getCanonicalQLClass() { result = "NEExpr" } + override string getAPrimaryQlClass() { result = "NEExpr" } override string getOperator() { result = "!=" } } @@ -78,7 +82,7 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr { * ``` */ class GTExpr extends RelationalOperation, @gtexpr { - override string getCanonicalQLClass() { result = "GTExpr" } + override string getAPrimaryQlClass() { result = "GTExpr" } override string getOperator() { result = ">" } @@ -94,7 +98,7 @@ class GTExpr extends RelationalOperation, @gtexpr { * ``` */ class LTExpr extends RelationalOperation, @ltexpr { - override string getCanonicalQLClass() { result = "LTExpr" } + override string getAPrimaryQlClass() { result = "LTExpr" } override string getOperator() { result = "<" } @@ -110,7 +114,7 @@ class LTExpr extends RelationalOperation, @ltexpr { * ``` */ class GEExpr extends RelationalOperation, @geexpr { - override string getCanonicalQLClass() { result = "GEExpr" } + override string getAPrimaryQlClass() { result = "GEExpr" } override string getOperator() { result = ">=" } @@ -126,7 +130,7 @@ class GEExpr extends RelationalOperation, @geexpr { * ``` */ class LEExpr extends RelationalOperation, @leexpr { - override string getCanonicalQLClass() { result = "LEExpr" } + override string getAPrimaryQlClass() { result = "LEExpr" } override string getOperator() { result = "<=" } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index 97371919b02..a24c08b4f05 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -1,3 +1,7 @@ +/** + * Provides classes modeling C/C++ expressions. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -53,7 +57,32 @@ class Expr extends StmtParent, @expr { Element getParent() { exprparents(underlyingElement(this), _, unresolveElement(result)) } /** Gets the location of this expression. */ - override Location getLocation() { exprs(underlyingElement(this), _, result) } + override Location getLocation() { + result = this.getExprLocationOverride() + or + not exists(this.getExprLocationOverride()) and + result = this.getDbLocation() + } + + /** + * Gets a location for this expression that's more accurate than + * `getDbLocation()`, if any. + */ + private Location getExprLocationOverride() { + // Base case: the parent has a better location than `this`. + this.getDbLocation() instanceof UnknownExprLocation and + result = this.getParent().(Expr).getDbLocation() and + not result instanceof UnknownLocation + or + // Recursive case: the parent has a location override that's better than + // what `this` has. + this.getDbLocation() instanceof UnknownExprLocation and + result = this.getParent().(Expr).getExprLocationOverride() and + not result instanceof UnknownLocation + } + + /** Gets the location of this expressions, raw from the database. */ + private Location getDbLocation() { exprs(underlyingElement(this), _, result) } /** Holds if this is an auxiliary expression generated by the compiler. */ predicate isCompilerGenerated() { @@ -540,7 +569,7 @@ class BinaryOperation extends Operation, @bin_op_expr { class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { override string toString() { result = "({...})" } - override string getCanonicalQLClass() { result = "ParenthesizedBracedInitializerList" } + override string getAPrimaryQlClass() { result = "ParenthesizedBracedInitializerList" } } /** @@ -555,7 +584,7 @@ class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { class ParenthesisExpr extends Conversion, @parexpr { override string toString() { result = "(...)" } - override string getCanonicalQLClass() { result = "ParenthesisExpr" } + override string getAPrimaryQlClass() { result = "ParenthesisExpr" } } /** @@ -566,7 +595,7 @@ class ParenthesisExpr extends Conversion, @parexpr { class ErrorExpr extends Expr, @errorexpr { override string toString() { result = "" } - override string getCanonicalQLClass() { result = "ErrorExpr" } + override string getAPrimaryQlClass() { result = "ErrorExpr" } } /** @@ -581,7 +610,7 @@ class ErrorExpr extends Expr, @errorexpr { class AssumeExpr extends Expr, @assume { override string toString() { result = "__assume(...)" } - override string getCanonicalQLClass() { result = "AssumeExpr" } + override string getAPrimaryQlClass() { result = "AssumeExpr" } /** * Gets the operand of the `__assume` expressions. @@ -596,7 +625,7 @@ class AssumeExpr extends Expr, @assume { * ``` */ class CommaExpr extends Expr, @commaexpr { - override string getCanonicalQLClass() { result = "CommaExpr" } + override string getAPrimaryQlClass() { result = "CommaExpr" } /** * Gets the left operand, which is the one whose value is discarded. @@ -631,7 +660,7 @@ class CommaExpr extends Expr, @commaexpr { * ``` */ class AddressOfExpr extends UnaryOperation, @address_of { - override string getCanonicalQLClass() { result = "AddressOfExpr" } + override string getAPrimaryQlClass() { result = "AddressOfExpr" } /** Gets the function or variable whose address is taken. */ Declaration getAddressable() { @@ -663,7 +692,7 @@ class AddressOfExpr extends UnaryOperation, @address_of { class ReferenceToExpr extends Conversion, @reference_to { override string toString() { result = "(reference to)" } - override string getCanonicalQLClass() { result = "ReferenceToExpr" } + override string getAPrimaryQlClass() { result = "ReferenceToExpr" } override int getPrecedence() { result = 16 } } @@ -677,7 +706,7 @@ class ReferenceToExpr extends Conversion, @reference_to { * ``` */ class PointerDereferenceExpr extends UnaryOperation, @indirect { - override string getCanonicalQLClass() { result = "PointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "PointerDereferenceExpr" } /** * DEPRECATED: Use getOperand() instead. @@ -715,7 +744,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect { class ReferenceDereferenceExpr extends Conversion, @ref_indirect { override string toString() { result = "(reference dereference)" } - override string getCanonicalQLClass() { result = "ReferenceDereferenceExpr" } + override string getAPrimaryQlClass() { result = "ReferenceDereferenceExpr" } } /** @@ -821,7 +850,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr { class NewExpr extends NewOrNewArrayExpr, @new_expr { override string toString() { result = "new" } - override string getCanonicalQLClass() { result = "NewExpr" } + override string getAPrimaryQlClass() { result = "NewExpr" } /** * Gets the type that is being allocated. @@ -851,7 +880,7 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr { class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { override string toString() { result = "new[]" } - override string getCanonicalQLClass() { result = "NewArrayExpr" } + override string getAPrimaryQlClass() { result = "NewArrayExpr" } /** * Gets the type that is being allocated. @@ -899,7 +928,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { class DeleteExpr extends Expr, @delete_expr { override string toString() { result = "delete" } - override string getCanonicalQLClass() { result = "DeleteExpr" } + override string getAPrimaryQlClass() { result = "DeleteExpr" } override int getPrecedence() { result = 16 } @@ -973,7 +1002,7 @@ class DeleteExpr extends Expr, @delete_expr { class DeleteArrayExpr extends Expr, @delete_array_expr { override string toString() { result = "delete[]" } - override string getCanonicalQLClass() { result = "DeleteArrayExpr" } + override string getAPrimaryQlClass() { result = "DeleteArrayExpr" } override int getPrecedence() { result = 16 } @@ -1053,7 +1082,7 @@ class StmtExpr extends Expr, @expr_stmt { */ Stmt getStmt() { result.getParent() = this } - override string getCanonicalQLClass() { result = "StmtExpr" } + override string getAPrimaryQlClass() { result = "StmtExpr" } /** * Gets the result expression of the enclosed statement. For example, @@ -1078,7 +1107,7 @@ private Expr getStmtResultExpr(Stmt stmt) { class ThisExpr extends Expr, @thisaccess { override string toString() { result = "this" } - override string getCanonicalQLClass() { result = "ThisExpr" } + override string getAPrimaryQlClass() { result = "ThisExpr" } override predicate mayBeImpure() { none() } @@ -1114,7 +1143,7 @@ class BlockExpr extends Literal { class NoExceptExpr extends Expr, @noexceptexpr { override string toString() { result = "noexcept(...)" } - override string getCanonicalQLClass() { result = "NoExceptExpr" } + override string getAPrimaryQlClass() { result = "NoExceptExpr" } /** * Gets the expression inside this noexcept expression. @@ -1146,7 +1175,7 @@ class FoldExpr extends Expr, @foldexpr { ) } - override string getCanonicalQLClass() { result = "FoldExpr" } + override string getAPrimaryQlClass() { result = "FoldExpr" } /** Gets the binary operator used in this fold expression, as a string. */ string getOperatorString() { fold(underlyingElement(this), result, _) } @@ -1222,7 +1251,7 @@ private predicate constantTemplateLiteral(Expr e) { * ``` */ class SpaceshipExpr extends BinaryOperation, @spaceshipexpr { - override string getCanonicalQLClass() { result = "SpaceshipExpr" } + override string getAPrimaryQlClass() { result = "SpaceshipExpr" } override int getPrecedence() { result = 11 } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index f634d9239b3..8a51001f4d5 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling lambda expressions and their captures. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class @@ -15,7 +19,7 @@ import semmle.code.cpp.Class class LambdaExpression extends Expr, @lambdaexpr { override string toString() { result = "[...](...){...}" } - override string getCanonicalQLClass() { result = "LambdaExpression" } + override string getAPrimaryQlClass() { result = "LambdaExpression" } /** * Gets an implicitly or explicitly captured value of this lambda expression. @@ -75,7 +79,7 @@ class LambdaExpression extends Expr, @lambdaexpr { class Closure extends Class { Closure() { exists(LambdaExpression e | this = e.getType()) } - override string getCanonicalQLClass() { result = "Closure" } + override string getAPrimaryQlClass() { result = "Closure" } /** Gets the lambda expression of which this is the type. */ LambdaExpression getLambdaExpression() { result.getType() = this } @@ -86,7 +90,7 @@ class Closure extends Class { result.getName() = "operator()" } - override string toString() { result = "decltype([...](...){...})" } + override string getDescription() { result = "decltype([...](...){...})" } } /** @@ -99,9 +103,9 @@ class Closure extends Class { * ``` */ class LambdaCapture extends Locatable, @lambdacapture { - override string toString() { result = getField().toString() } + override string toString() { result = getField().getName() } - override string getCanonicalQLClass() { result = "LambdaCapture" } + override string getAPrimaryQlClass() { result = "LambdaCapture" } /** * Holds if this capture was made implicitly. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index 3360be330c2..9ab944d2cc3 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling literals in the source code such as `0`, `'c'` + * or `"string"`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class Literal extends Expr, @literal { result = "Unknown literal" } - override string getCanonicalQLClass() { result = "Literal" } + override string getAPrimaryQlClass() { result = "Literal" } override predicate mayBeImpure() { none() } @@ -35,7 +40,7 @@ class Literal extends Expr, @literal { class LabelLiteral extends Literal { LabelLiteral() { jumpinfo(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "LabelLiteral" } + override string getAPrimaryQlClass() { result = "LabelLiteral" } /** Gets the corresponding label statement. */ LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -93,7 +98,7 @@ abstract class TextLiteral extends Literal { class CharLiteral extends TextLiteral { CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") } - override string getCanonicalQLClass() { result = "CharLiteral" } + override string getAPrimaryQlClass() { result = "CharLiteral" } /** * Gets the character of this literal. For example `L'a'` has character `"a"`. @@ -115,7 +120,7 @@ class StringLiteral extends TextLiteral { // @aggregateliteral rather than @literal. } - override string getCanonicalQLClass() { result = "StringLiteral" } + override string getAPrimaryQlClass() { result = "StringLiteral" } } /** @@ -128,7 +133,7 @@ class StringLiteral extends TextLiteral { class OctalLiteral extends Literal { OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "OctalLiteral" } + override string getAPrimaryQlClass() { result = "OctalLiteral" } } /** @@ -140,14 +145,14 @@ class OctalLiteral extends Literal { class HexLiteral extends Literal { HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "HexLiteral" } + override string getAPrimaryQlClass() { result = "HexLiteral" } } /** * A C/C++ aggregate literal. */ class AggregateLiteral extends Expr, @aggregateliteral { - override string getCanonicalQLClass() { result = "AggregateLiteral" } + override string getAPrimaryQlClass() { result = "AggregateLiteral" } /** * DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead. @@ -179,7 +184,7 @@ class ClassAggregateLiteral extends AggregateLiteral { ClassAggregateLiteral() { classType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ClassAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" } /** * Gets the expression within the aggregate literal that is used to initialize @@ -299,7 +304,7 @@ class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral { ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ArrayAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" } override int getArraySize() { result = arrayType.getArraySize() } @@ -323,7 +328,7 @@ class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral { VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "VectorAggregateLiteral" } + override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" } override int getArraySize() { result = vectorType.getNumElements() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll index fa55c1e91eb..d0e207f7b31 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling logical operations such as `!`, `&&`, `||`, and + * the ternary `? :` expression. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { } class NotExpr extends UnaryLogicalOperation, @notexpr { override string getOperator() { result = "!" } - override string getCanonicalQLClass() { result = "NotExpr" } + override string getAPrimaryQlClass() { result = "NotExpr" } override int getPrecedence() { result = 16 } } @@ -46,7 +51,7 @@ class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr { class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { override string getOperator() { result = "&&" } - override string getCanonicalQLClass() { result = "LogicalAndExpr" } + override string getAPrimaryQlClass() { result = "LogicalAndExpr" } override int getPrecedence() { result = 5 } @@ -67,7 +72,7 @@ class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr { override string getOperator() { result = "||" } - override string getCanonicalQLClass() { result = "LogicalOrExpr" } + override string getAPrimaryQlClass() { result = "LogicalOrExpr" } override int getPrecedence() { result = 4 } @@ -89,7 +94,7 @@ class ConditionalExpr extends Operation, @conditionalexpr { /** Gets the condition of this conditional expression. */ Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConditionalExpr" } + override string getAPrimaryQlClass() { result = "ConditionalExpr" } /** Gets the 'then' expression of this conditional expression. */ Expr getThen() { diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll index 61699023f8f..c651ae9b153 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll @@ -1,3 +1,7 @@ +/** + * DEPRECATED: Objective-C is no longer supported. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class import semmle.code.cpp.ObjectiveC diff --git a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll index 5152e3005f3..436be8384e8 100644 --- a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll +++ b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll @@ -1,3 +1,11 @@ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp predicate addressConstantExpression(Expr e) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f019f20b6a8..381adad5e41 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + // Most queries should operate on the aliased SSA IR, so that's what we expose -// publically as the "IR". +// publicly as the "IR". import implementation.aliased_ssa.IR diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll index b5b7d7de7c2..b8abef8a547 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll @@ -1 +1,5 @@ +/** + * Module used to configure the IR generation process. + */ + import implementation.IRConfiguration diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql new file mode 100644 index 00000000000..1a1c2e369cc --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ir-consistency-check + */ + +import implementation.aliased_ssa.IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql deleted file mode 100644 index 2c2c6e348a1..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ir-sanity-check - */ - -import implementation.aliased_ssa.IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll index 3ff80237635..c4ebf2f1eba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll @@ -1 +1,11 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + import implementation.aliased_ssa.PrintIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index dbeefae4880..ddf43651727 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -1,10 +1,12 @@ import cpp import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.DataFlow2 private import semmle.code.cpp.ir.dataflow.DataFlow3 private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch +private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow @@ -31,8 +33,7 @@ private predicate predictableInstruction(Instruction instr) { * Note that the list itself is not very principled; it consists of all the * functions listed in the old security library's [default] `isPureFunction` * that have more than one argument, but are not in the old taint tracking - * library's `returnArgument` predicate. In addition, `strlen` is included - * because it's also a special case in flow to return values. + * library's `returnArgument` predicate. */ predicate predictableOnlyFlow(string name) { name = "strcasestr" or @@ -41,7 +42,6 @@ predicate predictableOnlyFlow(string name) { name = "strchrnul" or name = "strcmp" or name = "strcspn" or - name = "strlen" or // special case name = "strncmp" or name = "strndup" or name = "strnlen" or @@ -67,6 +67,9 @@ private DataFlow::Node getNodeForSource(Expr source) { // to `gets`. It's impossible here to tell which is which, but the "access // to argv" source is definitely not intended to match an output argument, // and it causes false positives if we let it. + // + // This case goes together with the similar (but not identical) rule in + // `nodeIsBarrierIn`. result = DataFlow::definitionByReferenceNode(source) and not argv(source.(VariableAccess).getTarget()) ) @@ -170,16 +173,45 @@ private predicate hasUpperBoundsCheck(Variable var) { ) } +private predicate nodeIsBarrierEqualityCandidate( + DataFlow::Node node, Operand access, Variable checkedVar +) { + readsVariable(node.asInstruction(), checkedVar) and + any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) +} + private predicate nodeIsBarrier(DataFlow::Node node) { exists(Variable checkedVar | readsVariable(node.asInstruction(), checkedVar) and hasUpperBoundsCheck(checkedVar) ) + or + exists(Variable checkedVar, Operand access | + /* + * This node is guarded by a condition that forces the accessed variable + * to equal something else. For example: + * ``` + * x = taintsource() + * if (x == 10) { + * taintsink(x); // not considered tainted + * } + * ``` + */ + + nodeIsBarrierEqualityCandidate(node, access, checkedVar) and + readsVariable(access.getDef(), checkedVar) + ) } private predicate nodeIsBarrierIn(DataFlow::Node node) { // don't use dataflow into taint sources, as this leads to duplicate results. - node = getNodeForSource(any(Expr e)) + exists(Expr source | isUserInput(source, _) | + node = DataFlow::exprNode(source) + or + // This case goes together with the similar (but not identical) rule in + // `getNodeForSource`. + node = DataFlow::definitionByReferenceNode(source) + ) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index 1dd1d9ac4cc..e927634fec2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -77,51 +77,48 @@ private module VirtualDispatch { // Local flow DataFlow::localFlowStep(src, other) and allowFromArg = allowOtherFromArg - ) - or - // Flow through global variable - exists(StoreInstruction store | - store = src.asInstruction() and - ( - exists(Variable var | - var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and - this.flowsFromGlobal(var) - ) - or - exists(Variable var, FieldAccess a | - var = - store - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .(VariableAddressInstruction) - .getASTVariable() and - this.flowsFromGlobalUnionField(var, a) - ) - ) and - allowFromArg = true + or + // Flow from global variable to load. + exists(LoadInstruction load, GlobalOrNamespaceVariable var | + var = src.asVariable() and + other.asInstruction() = load and + addressOfGlobal(load.getSourceAddress(), var) and + // The `allowFromArg` concept doesn't play a role when `src` is a + // global variable, so we just set it to a single arbitrary value for + // performance. + allowFromArg = true + ) + or + // Flow from store to global variable. + exists(StoreInstruction store, GlobalOrNamespaceVariable var | + var = other.asVariable() and + store = src.asInstruction() and + storeIntoGlobal(store, var) and + // Setting `allowFromArg` to `true` like in the base case means we + // treat a store to a global variable like the dispatch itself: flow + // may come from anywhere. + allowFromArg = true + ) ) } + } - private predicate flowsFromGlobal(GlobalOrNamespaceVariable var) { - exists(LoadInstruction load | - this.flowsFrom(DataFlow::instructionNode(load), _) and - load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var - ) - } + pragma[noinline] + private predicate storeIntoGlobal(StoreInstruction store, GlobalOrNamespaceVariable var) { + addressOfGlobal(store.getDestinationAddress(), var) + } - private predicate flowsFromGlobalUnionField(Variable var, FieldAccess a) { - a.getTarget().getDeclaringType() instanceof Union and - exists(LoadInstruction load | - this.flowsFrom(DataFlow::instructionNode(load), _) and - load - .getSourceAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .(VariableAddressInstruction) - .getASTVariable() = var - ) - } + /** Holds if `addressInstr` is an instruction that produces the address of `var`. */ + private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) { + // Access directly to the global variable + addressInstr.(VariableAddressInstruction).getASTVariable() = var + or + // Access to a field on a global union + exists(FieldAddressInstruction fa | + fa = addressInstr and + fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and + fa.getField().getDeclaringType() instanceof Union + ) } /** @@ -229,28 +226,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(CallInstruction call, Function f, CallInstruction ctx) { - none() -} +predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. */ -Function prunedViableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, CallInstruction call) { none() } - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ -Function prunedViableImplInCallContextReverse(CallInstruction call, CallInstruction ctx) { none() } +Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index b241a574c97..27ab1d01feb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,13 +289,94 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) + ) } /** @@ -340,21 +387,10 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,26 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -564,6 +615,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +637,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +649,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +663,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } @@ -665,9 +730,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -679,6 +741,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -689,25 +768,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 531fcdfd368..01e3f12af4f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -8,16 +8,28 @@ private import DataFlowDispatch * to the callable. Instance arguments (`this` pointer) are also included. */ class ArgumentNode extends InstructionNode { - ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) } + ArgumentNode() { + exists(CallInstruction call | + instr = call.getAnArgument() + or + instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call + ) + } /** * Holds if this argument occurs at the given position in the given call. * The instance argument is considered to have index `-1`. */ predicate argumentOf(DataFlowCall call, int pos) { - this.getInstruction() = call.getPositionalArgument(pos) + instr = call.getPositionalArgument(pos) or - this.getInstruction() = call.getThisArgument() and pos = -1 + instr = call.getThisArgument() and pos = -1 + or + exists(ReadSideEffectInstruction read | + read = instr and + read.getPrimaryInstruction() = call and + pos = getArgumentPosOfSideEffect(read.getIndex()) + ) } /** Gets the call in which this node is an argument. */ @@ -74,7 +86,12 @@ class ReturnValueNode extends ReturnNode { class ReturnIndirectionNode extends ReturnNode { override ReturnIndirectionInstruction primary; - override ReturnKind getKind() { result = TIndirectReturnKind(primary.getParameter().getIndex()) } + override ReturnKind getKind() { + result = TIndirectReturnKind(-1) and + primary.isThisIndirection() + or + result = TIndirectReturnKind(primary.getParameter().getIndex()) + } } /** A data flow node that represents the output of a call. */ @@ -111,8 +128,13 @@ private class SideEffectOutNode extends OutNode { * `kind`. */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { - result.getCall() = call and - result.getReturnKind() = kind + // There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that + // this is true helps it make better decisions downstream, especially in virtual dispatch. + result = + unique(OutNode outNode | + outNode.getCall() = call and + outNode.getReturnKind() = kind + ) } /** @@ -138,12 +160,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { @@ -158,26 +174,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override Type getContainerType() { result = f.getDeclaringType() } - - override Type getType() { result = f.getType() } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { @@ -223,28 +227,31 @@ predicate readStep(Node node1, Content f, Node node2) { } /** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. + * Holds if values stored inside content `c` are cleared at node `n`. */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and - result instanceof VoidType // stub implementation +predicate clearsContent(Node n, Content c) { + none() // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ -string ppReprType(Type t) { none() } // stub implementation +/** Gets the type of `n` used for type pruning. */ +IRType getNodeType(Node n) { + suppressUnusedNode(n) and + result instanceof IRVoidType // stub implementation +} + +/** Gets a string representation of a type returned by `getNodeType`. */ +string ppReprType(IRType t) { none() } // stub implementation /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. */ pragma[inline] -predicate compatibleTypes(Type t1, Type t2) { +predicate compatibleTypes(IRType t1, IRType t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers @@ -264,7 +271,7 @@ class DataFlowCallable = Declaration; class DataFlowExpr = Expr; -class DataFlowType = Type; +class DataFlowType = IRType; /** A function call relevant for data flow. */ class DataFlowCall extends CallInstruction { @@ -294,3 +301,6 @@ predicate isImmutableOrUnobservable(Node n) { // complex to model here. any() } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { n instanceof OperandNode } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..a784552d15c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -13,6 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or + TOperandNode(Operand op) or TVariableNode(Variable var) /** @@ -32,11 +33,14 @@ class Node extends TIRDataFlowNode { Function getFunction() { none() } // overridden in subclasses /** Gets the type of this node. */ - Type getType() { none() } // overridden in subclasses + IRType getType() { none() } // overridden in subclasses /** Gets the instruction corresponding to this node, if any. */ Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } + /** Gets the operands corresponding to this node, if any. */ + Operand asOperand() { result = this.(OperandNode).getOperand() } + /** * Gets the non-conversion expression corresponding to this node, if any. If * this node strictly (in the sense of `asConvertedExpr`) corresponds to a @@ -54,12 +58,12 @@ class Node extends TIRDataFlowNode { /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */ Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() } - /** Gets the parameter corresponding to this node, if any. */ + /** Gets the positional parameter corresponding to this node, if any. */ Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() } /** * Gets the variable corresponding to this node, if any. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ Variable asVariable() { result = this.(VariableNode).getVariable() } @@ -71,9 +75,7 @@ class Node extends TIRDataFlowNode { * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is * a partial definition of `&x`). */ - Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression() - } + Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() } /** * DEPRECATED: See UninitializedNode. @@ -86,7 +88,7 @@ class Node extends TIRDataFlowNode { /** * Gets an upper bound on the type of this node. */ - Type getTypeBound() { result = getType() } + IRType getTypeBound() { result = getType() } /** Gets the location of this element. */ Location getLocation() { none() } // overridden by subclasses @@ -123,7 +125,7 @@ class InstructionNode extends Node, TInstructionNode { override Function getFunction() { result = instr.getEnclosingFunction() } - override Type getType() { result = instr.getResultType() } + override IRType getType() { result = instr.getResultIRType() } override Location getLocation() { result = instr.getLocation() } @@ -134,6 +136,28 @@ class InstructionNode extends Node, TInstructionNode { } } +/** + * An operand, viewed as a node in a data flow graph. + */ +class OperandNode extends Node, TOperandNode { + Operand op; + + OperandNode() { this = TOperandNode(op) } + + /** Gets the operand corresponding to this node. */ + Operand getOperand() { result = op } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = op.getUse().getEnclosingFunction() } + + override IRType getType() { result = op.getIRType() } + + override Location getLocation() { result = op.getLocation() } + + override string toString() { result = this.getOperand().toString() } +} + /** * An expression, viewed as a node in a data flow graph. */ @@ -158,48 +182,90 @@ class ExprNode extends InstructionNode { } /** - * A node representing a `Parameter`. This includes both explicit parameters such - * as `x` in `f(x)` and implicit parameters such as `this` in `x.f()` + * INTERNAL: do not use. Translates a parameter/argument index into a negative + * number that denotes the index of its side effect (pointer indirection). */ -class ParameterNode extends InstructionNode { - ParameterNode() { - instr instanceof InitializeParameterInstruction - or - instr instanceof InitializeThisInstruction - } - - /** - * Holds if this node is the parameter of `c` at the specified (zero-based) - * position. The implicit `this` parameter is considered to have index `-1`. - */ - predicate isParameterOf(Function f, int i) { none() } // overriden by subclasses +bindingset[index] +int getArgumentPosOfSideEffect(int index) { + // -1 -> -2 + // 0 -> -3 + // 1 -> -4 + // ... + result = -3 - index } /** * The value of a parameter at function entry, viewed as a node in a data - * flow graph. + * flow graph. This includes both explicit parameters such as `x` in `f(x)` + * and implicit parameters such as `this` in `x.f()`. + * + * To match a specific kind of parameter, consider using one of the subclasses + * `ExplicitParameterNode`, `ThisParameterNode`, or + * `ParameterIndirectionNode`. */ +class ParameterNode extends InstructionNode { + ParameterNode() { + // To avoid making this class abstract, we enumerate its values here + instr instanceof InitializeParameterInstruction + or + instr instanceof InitializeIndirectionInstruction + } + + /** + * Holds if this node is the parameter of `f` at the specified position. The + * implicit `this` parameter is considered to have position `-1`, and + * pointer-indirection parameters are at further negative positions. + */ + predicate isParameterOf(Function f, int pos) { none() } // overridden by subclasses +} + +/** An explicit positional parameter, not including `this` or `...`. */ private class ExplicitParameterNode extends ParameterNode { override InitializeParameterInstruction instr; - override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() } + ExplicitParameterNode() { exists(instr.getParameter()) } - /** Gets the parameter corresponding to this node. */ + override predicate isParameterOf(Function f, int pos) { + f.getParameter(pos) = instr.getParameter() + } + + /** Gets the `Parameter` associated with this node. */ Parameter getParameter() { result = instr.getParameter() } override string toString() { result = instr.getParameter().toString() } } -private class ThisParameterNode extends ParameterNode { - override InitializeThisInstruction instr; +/** An implicit `this` parameter. */ +class ThisParameterNode extends ParameterNode { + override InitializeParameterInstruction instr; - override predicate isParameterOf(Function f, int i) { - i = -1 and instr.getEnclosingFunction() = f + ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable } + + override predicate isParameterOf(Function f, int pos) { + pos = -1 and instr.getEnclosingFunction() = f } override string toString() { result = "this" } } +/** A synthetic parameter to model the pointed-to object of a pointer parameter. */ +class ParameterIndirectionNode extends ParameterNode { + override InitializeIndirectionInstruction instr; + + override predicate isParameterOf(Function f, int pos) { + exists(int index | + f.getParameter(index) = instr.getParameter() + or + index = -1 and + instr.getIRVariable().(IRThisVariable).getEnclosingFunction() = f + | + pos = getArgumentPosOfSideEffect(index) + ) + } + + override string toString() { result = "*" + instr.getIRVariable().toString() } +} + /** * DEPRECATED: Data flow was never an accurate way to determine what * expressions might be uninitialized. It errs on the side of saying that @@ -251,23 +317,30 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract private class PartialDefinitionNode extends PostUpdateNode { + abstract Expr getDefinedExpr(); +} private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; + FieldAddressInstruction field; ExplicitFieldStoreQualifierNode() { not instr.isResultConflated() and - exists(StoreInstruction store, FieldInstruction field | + exists(StoreInstruction store | instr.getPartial() = store and field = store.getDestinationAddress() ) } - // There might be multiple `ChiInstructions` that has a particular instruction as - // the total operand - so this definition gives consistency errors in - // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications - // this consistency failure has. - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors + // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause + // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node + // into a big step. + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** @@ -278,15 +351,18 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { */ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { override StoreInstruction instr; + FieldAddressInstruction field; ExplicitSingleFieldStoreQualifierNode() { - exists(FieldAddressInstruction field | - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) - ) + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) } override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** @@ -337,10 +413,22 @@ class DefinitionByReferenceNode extends InstructionNode { } } +/** + * A node representing the memory pointed to by a function argument. + * + * This class exists only in order to override `toString`, which would + * otherwise be the default implementation inherited from `InstructionNode`. + */ +private class ArgumentIndirectionNode extends InstructionNode { + override ReadSideEffectInstruction instr; + + override string toString() { result = "Argument " + instr.getIndex() + " indirection" } +} + /** * A `Node` corresponding to a variable in the program, as opposed to the * value of that variable at some particular point. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ class VariableNode extends Node, TVariableNode { Variable v; @@ -361,7 +449,7 @@ class VariableNode extends Node, TVariableNode { result = v } - override Type getType() { result = v.getType() } + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } @@ -420,7 +508,11 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr * data flow. It may have less flow than the `localFlowStep` predicate. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + // Instruction -> Instruction flow simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + // Operand -> Instruction flow + simpleOperandLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) } pragma[noinline] @@ -432,12 +524,47 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) { ) } +private predicate simpleOperandLocalFlowStep(Operand opFrom, Instruction iTo) { + // Certain dataflow steps (for instance `PostUpdateNode.getPreUpdateNode()`) generates flow to + // operands, so we include dataflow from those operands to the "result" of the instruction (i.e., to + // the instruction itself). + exists(PostUpdateNode post | + opFrom = post.getPreUpdateNode().asOperand() and + iTo.getAnOperand() = opFrom + ) +} + cached private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { iTo.(CopyInstruction).getSourceValue() = iFrom or iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or + // A read side effect is almost never exact since we don't know exactly how + // much memory the callee will read. + iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and + not iFrom.isResultConflated() + or + // Loading a single `int` from an `int *` parameter is not an exact load since + // the parameter may point to an entire array rather than a single `int`. The + // following rule ensures that any flow going into the + // `InitializeIndirectionInstruction`, even if it's for a different array + // element, will propagate to a load of the first element. + // + // Since we're linking `InitializeIndirectionInstruction` and + // `LoadInstruction` together directly, this rule will break if there's any + // reassignment of the parameter indirection, including a conditional one that + // leads to a phi node. + exists(InitializeIndirectionInstruction init | + iFrom = init and + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and + // Check that the types match. Otherwise we can get flow from an object to + // its fields, which leads to field conflation when there's flow from other + // fields to the object elsewhere. + init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() = + iTo.getResultType().getUnspecifiedType() + ) + or // Treat all conversions as flow, even conversions between different numeric types. iTo.(ConvertInstruction).getUnary() = iFrom or @@ -458,9 +585,9 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or - // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. - // First, we add flow from write side-effects to non-conflated chi instructions through their - // partial operands. Consider the following example: + // Add flow from write side-effects to non-conflated chi instructions through their + // partial operands. From there, a `readStep` will find subsequent reads of that field. + // Consider the following example: // ``` // void setX(Point* p, int new_x) { // p->x = new_x; @@ -470,22 +597,18 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // ``` // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to // `setX`, which will be melded into `p` through a chi instruction. - iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and - not iTo.isResultConflated() - or - // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). - // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. - exists(ChiInstruction chi | iFrom = chi | - not chi.isResultConflated() and - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi + exists(ChiInstruction chi | chi = iTo | + chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and + not chi.isResultConflated() ) or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and - exists(int size, Type type | + exists(int size, Type type, Class cTo | type = iFrom.getResultType() and - iTo.getResultType().getSize() = size and - getFieldSizeOfClass(iTo.getResultType(), type, size) + cTo = iTo.getResultType() and + cTo.getSize() = size and + getFieldSizeOfClass(cTo, type, size) ) or // Flow through modeled functions diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 650c15f189a..32e36bb6787 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -17,6 +21,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,8 +33,6 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } -GotoEdge gotoEdge() { result = TGotoEdge() } - /** * A "true" edge, representing the successor of a conditional branch when the * condition is non-zero. @@ -38,8 +41,6 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } -TrueEdge trueEdge() { result = TTrueEdge() } - /** * A "false" edge, representing the successor of a conditional branch when the * condition is zero. @@ -48,8 +49,6 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } -FalseEdge falseEdge() { result = TFalseEdge() } - /** * An "exception" edge, representing the successor of an instruction when that * instruction's evaluation throws an exception. @@ -58,8 +57,6 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } -ExceptionEdge exceptionEdge() { result = TExceptionEdge() } - /** * A "default" edge, representing the successor of a `Switch` instruction when * none of the case values matches the condition value. @@ -68,8 +65,6 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } -DefaultEdge defaultEdge() { result = TDefaultEdge() } - /** * A "case" edge, representing the successor of a `Switch` instruction when the * the condition value matches a correponding `case` label. @@ -86,9 +81,59 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } -CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +/** + * Predicates to access the single instance of each `EdgeKind` class. + */ +module EdgeKind { + /** + * Gets the single instance of the `GotoEdge` class. + */ + GotoEdge gotoEdge() { result = TGotoEdge() } + + /** + * Gets the single instance of the `TrueEdge` class. + */ + TrueEdge trueEdge() { result = TTrueEdge() } + + /** + * Gets the single instance of the `FalseEdge` class. + */ + FalseEdge falseEdge() { result = TFalseEdge() } + + /** + * Gets the single instance of the `ExceptionEdge` class. + */ + ExceptionEdge exceptionEdge() { result = TExceptionEdge() } + + /** + * Gets the single instance of the `DefaultEdge` class. + */ + DefaultEdge defaultEdge() { result = TDefaultEdge() } + + /** + * Gets the `CaseEdge` representing a `case` label with the specified lower and upper bounds. + * For example: + * ``` + * switch (x) { + * case 1: // Edge kind is `caseEdge("1", "1")` + * return x; + * case 2...8: // Edge kind is `caseEdge("2", "8")` + * return x - 1; + * default: // Edge kind is `defaultEdge()` + * return 0; + * } + * ``` + */ + CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 9a75ca19154..3bf3bf2e276 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** @@ -111,6 +112,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -128,7 +131,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -137,13 +140,33 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. +} + +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -152,13 +175,15 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -167,6 +192,8 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** @@ -275,12 +302,24 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } -module IRTypeSanity { +/** + * INTERNAL: Do not use. + * Query predicates used to check invariants that should hold for all `IRType` objects. To run all + * consistency queries for the IR, including the ones below, run + * "semmle/code/cpp/IR/IRConsistency.ql". + */ +module IRTypeConsistency { + /** + * Holds if the type has no result for `IRType.getCanonicalLanguageType()`. + */ query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" } + /** + * Holds if the type has more than one result for `IRType.getCanonicalLanguageType()`. + */ query predicate multipleCanonicalLanguageTypes(IRType type, string message) { strictcount(type.getCanonicalLanguageType()) > 1 and message = @@ -288,11 +327,17 @@ module IRTypeSanity { concat(type.getCanonicalLanguageType().toString(), ", ") } + /** + * Holds if the type has no result for `LanguageType.getIRType()`. + */ query predicate missingIRType(Language::LanguageType type, string message) { not exists(type.getIRType()) and message = "`LanguageType` does not have a corresponding `IRType`." } + /** + * Holds if the type has more than one result for `LanguageType.getIRType()`. + */ query predicate multipleIRTypes(Language::LanguageType type, string message) { strictcount(type.getIRType()) > 1 and message = @@ -300,5 +345,5 @@ module IRTypeSanity { concat(type.getIRType().toString(), ", ") } - import Language::LanguageTypeSanity + import Language::LanguageTypeConsistency } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index eac4d333afc..5e11a310e2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** @@ -92,11 +99,3 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess { class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess { override string toString() { result = "chi(partial)" } } - -/** - * The operand accesses memory not modeled in SSA. Used only on the result of - * `UnmodeledDefinition` and on the operands of `UnmodeledUse`. - */ -class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess { - override string toString() { result = "unmodeled" } -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index e7a0b6f1b4f..c4134d240ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -45,7 +50,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -60,8 +65,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -88,7 +91,11 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** @@ -141,10 +148,20 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -152,44 +169,127 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. + */ abstract class CopyOpcode extends Opcode { } +/** + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - +/** + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. + */ abstract class ReturnOpcode extends Opcode { } +/** + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. + */ abstract class ThrowOpcode extends Opcode { } +/** + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. + */ abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -325,7 +425,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -334,51 +436,111 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { + /** + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -387,14 +549,29 @@ module Opcode { } } + /** + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -403,154 +580,344 @@ module Opcode { } } + /** + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + /** + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. + */ + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } + /** + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -559,48 +926,67 @@ module Opcode { } } + /** + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } - class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { - final override string toString() { result = "UnmodeledDefinition" } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof UnmodeledMemoryAccess - } - } - - class UnmodeledUse extends Opcode, TUnmodeledUse { - final override string toString() { result = "UnmodeledUse" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof UnmodeledUseOperandTag - } - } - + /** + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -609,6 +995,11 @@ module Opcode { } } + /** + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -619,92 +1010,187 @@ module Opcode { } } + /** + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -719,6 +1205,11 @@ module Opcode { } } + /** + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -728,10 +1219,20 @@ module Opcode { } } + /** + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index ec6de78cfa4..5f230de560d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -1,6 +1,17 @@ +/** + * Defines the public interface to temporary variable tags, which describe the reason a particular + * `IRTempVariable` was generated. + */ + private import internal.TempVariableTagInternal private import Imports::TempVariableTag +/** + * A reason that a particular IR temporary variable was generated. For example, it could be + * generated to hold the return value of a function, or to hold the result of a `?:` operator + * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. + */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index badd48552a5..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index dce1717bdc9..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,49 +20,89 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -70,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -91,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -206,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..0b49f422bab --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Aliased SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/aliased-ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll new file mode 100644 index 00000000000..6a87b9b4b5f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(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) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + 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, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * 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, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * 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, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + 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 + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 1e9c2d1d913..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ @@ -40,16 +28,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql deleted file mode 100644 index b5d3ae4633e..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Aliased SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/aliased-ssa-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -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 Imports::Overlap - 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 a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * 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()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 0d5e7fe595c..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,10 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } +} + +/** + * A temporary variable generated to hold the `this` pointer. + */ +class IRThisVariable extends IRTempVariable, IRParameter { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -240,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -257,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -265,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 780f636ff10..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -320,8 +343,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -393,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -408,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -475,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -497,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -506,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -542,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is true. + */ + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -635,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -779,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -858,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -868,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -878,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -888,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -898,16 +1466,33 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + /** Gets the successor instruction along the default edge of the switch, if any. */ + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -937,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -982,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -997,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1047,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1057,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1088,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1104,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1112,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1119,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1212,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1230,10 +1854,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ @@ -1248,12 +1868,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * @@ -1351,26 +1965,33 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1383,3 +2004,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 1836f4c4b2f..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -14,16 +18,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -31,14 +27,72 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the register operand with the specified parameters. + */ +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the non-Phi memory operand with the specified parameters. + */ +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) +} + +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); +} + +/** + * Returns the Phi operand with the specified parameters. + */ +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -104,7 +158,17 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** @@ -169,8 +233,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,30 +268,37 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { result = defInstr } final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. @@ -235,15 +306,33 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +/** + * A memory operand other than the operand of a `Phi` instruction. + */ +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } - final override Overlap getDefinitionOverlap() { result = overlap } + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -258,8 +347,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +355,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +363,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +370,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +377,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +384,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +391,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +398,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } -} - -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } } /** @@ -342,8 +405,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +422,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +429,30 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -427,8 +482,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -438,7 +491,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index d9c0df44e12..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -47,7 +58,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +235,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 13d19587135..796fb792366 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" + this instanceof TConstantValueNumber and result = "Constant" or this instanceof TStringConstantValueNumber and result = "StringConstant" or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..19fb0490f80 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and @@ -247,6 +248,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll index e95086c89fc..69cd6e6dc29 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll @@ -5,7 +5,7 @@ private import AliasAnalysis private newtype TAllocation = TVariableAllocation(IRVariable var) or - TIndirectParameterAllocation(IRAutomaticUserVariable var) { + TIndirectParameterAllocation(IRAutomaticVariable var) { exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var) } or TDynamicAllocation(CallInstruction call) { @@ -74,7 +74,7 @@ class VariableAllocation extends Allocation, TVariableAllocation { } class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocation { - IRAutomaticUserVariable var; + IRAutomaticVariable var; IndirectParameterAllocation() { this = TIndirectParameterAllocation(var) } @@ -90,7 +90,7 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati final override string getUniqueId() { result = var.getUniqueId() } - final override IRType getIRType() { result = var.getIRType() } + final override IRType getIRType() { result instanceof IRUnknownType } final override predicate isReadOnly() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll index 4cc52d3bbf9..3a7a08accc0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..3379f4530a1 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Aliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/aliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 155934689b6..ae0e03e97da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,47 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -67,15 +66,13 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -83,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -127,40 +124,13 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap @@ -201,13 +171,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -220,7 +192,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -232,21 +204,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -257,20 +219,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -289,137 +251,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() + or + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + instr = unreachedInstruction(_) and result = Language::getVoidType() + } + + cached + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() + or + instr = phiInstruction(_, _) and result instanceof Opcode::Phi + or + instr = chiInstruction(_) and result instanceof Opcode::Chi + or + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached + } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() + or + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(_) and - result = Language::getVoidType() - } - - cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) or - instruction instanceof Chi and - result instanceof Opcode::Chi - or - instruction instanceof Phi and - result instanceof Opcode::Phi - or - instruction instanceof Unreached and - result instanceof Opcode::Unreached - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) - or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) - or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) + instr = unreachedInstruction(result) } cached @@ -430,7 +328,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -438,6 +336,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -617,7 +523,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -636,7 +542,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -920,7 +826,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -930,7 +836,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -941,7 +847,10 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -954,6 +863,9 @@ module SSASanity { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -962,4 +874,41 @@ module SSASanity { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } +} + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29..f347df86ba1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index c0922aff891..bb068bdd489 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 3bd709a93dc..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Aliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id cpp/aliased-ssa-sanity-check - */ - -import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 00000000000..60895ce3d26 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,27 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ + +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 00000000000..cc1bdb6444b --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index 227b1a34041..ac284440648 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -1,3 +1,8 @@ +/** + * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` + * plays in the evaluation of its `Instruction`. + */ + private import OperandTagInternal private newtype TOperandTag = @@ -10,7 +15,6 @@ private newtype TOperandTag = TLeftOperand() or TRightOperand() or TConditionOperand() or - TUnmodeledUseOperand() or TCallTargetOperand() or TThisArgumentOperand() or TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or @@ -24,10 +28,18 @@ private newtype TOperandTag = * an `Instruction` is determined by the instruction's opcode. */ abstract class OperandTag extends TOperandTag { + /** Gets a textual representation of this operand tag */ abstract string toString(); + /** + * Gets an integer that represents where this this operand will appear in the operand list of an + * instruction when the IR is printed. + */ abstract int getSortOrder(); + /** + * Gets a label that will appear before the operand when the IR is printed. + */ string getLabel() { result = "" } } @@ -47,7 +59,7 @@ abstract class RegisterOperandTag extends OperandTag { } abstract class TypedOperandTag extends MemoryOperandTag { } // Note: individual subtypes are listed in the order that the operands should -// appear in the operand list of the instruction when printing. +// appear in the operand list of the instruction when the IR is printed. /** * The address operand of an instruction that loads or stores a value from * memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`). @@ -152,18 +164,6 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { ConditionOperandTag conditionOperand() { result = TConditionOperand() } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand { - final override string toString() { result = "UnmodeledUse" } - - final override int getSortOrder() { result = 9 } -} - -UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() } - /** * The operand representing the target function of an `Call` instruction. */ @@ -221,7 +221,9 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { +abstract class ChiOperandTag extends MemoryOperandTag { } + +class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } final override int getSortOrder() { result = 13 } @@ -231,7 +233,7 @@ class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } -class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand { +class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override string toString() { result = "ChiPartial" } final override int getSortOrder() { result = 14 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll index 362274f387c..7984c4883fd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll @@ -1,5 +1,5 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll new file mode 100644 index 00000000000..e16b71733b5 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,97 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +cached +newtype TInstruction = + TRawInstruction( + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 00000000000..e008ce7d8d3 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType +import semmle.code.cpp.ir.implementation.Opcode as Opcode diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 00000000000..adaaaca9cd8 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index badd48552a5..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index dce1717bdc9..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,49 +20,89 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -70,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -91,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -206,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql new file mode 100644 index 00000000000..0d8dd13543b --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Raw IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/raw-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll new file mode 100644 index 00000000000..6a87b9b4b5f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(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) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + 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, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * 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, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * 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, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + 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 + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 1e9c2d1d913..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ @@ -40,16 +28,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql deleted file mode 100644 index a9d6b7943fe..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Raw IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/raw-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -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 Imports::Overlap - 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 a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * 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()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 0d5e7fe595c..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,10 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } +} + +/** + * A temporary variable generated to hold the `this` pointer. + */ +class IRThisVariable extends IRTempVariable, IRParameter { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -240,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -257,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -265,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 780f636ff10..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -320,8 +343,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -393,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -408,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -475,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -497,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -506,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -542,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is true. + */ + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -635,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -779,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -858,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -868,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -878,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -888,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -898,16 +1466,33 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + /** Gets the successor instruction along the default edge of the switch, if any. */ + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -937,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -982,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -997,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1047,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1057,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1088,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1104,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1112,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1119,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1212,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1230,10 +1854,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ @@ -1248,12 +1868,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * @@ -1351,26 +1965,33 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1383,3 +2004,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 1836f4c4b2f..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -14,16 +18,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -31,14 +27,72 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the register operand with the specified parameters. + */ +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the non-Phi memory operand with the specified parameters. + */ +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) +} + +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); +} + +/** + * Returns the Phi operand with the specified parameters. + */ +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -104,7 +158,17 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** @@ -169,8 +233,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,30 +268,37 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { result = defInstr } final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. @@ -235,15 +306,33 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +/** + * A memory operand other than the operand of a `Phi` instruction. + */ +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } - final override Overlap getDefinitionOverlap() { result = overlap } + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -258,8 +347,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +355,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +363,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +370,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +377,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +384,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +391,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +398,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } -} - -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } } /** @@ -342,8 +405,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +422,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +429,30 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -427,8 +482,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -438,7 +491,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index d9c0df44e12..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -47,7 +58,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +235,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..796fb792366 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" + this instanceof TConstantValueNumber and result = "Constant" or this instanceof TStringConstantValueNumber and result = "StringConstant" or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 18a77452929..15200491e98 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,9 @@ private import cpp import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase +private import semmle.code.cpp.ir.implementation.internal.TInstruction +private import semmle.code.cpp.ir.implementation.internal.TIRVariable private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.Overlap private import semmle.code.cpp.ir.internal.TempVariableTag @@ -12,23 +15,30 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } - -import Cached +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, result) +} +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; + cached predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) } cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) + } cached predicate hasUserVariable(Function func, Variable var, CppType type) { @@ -59,236 +69,7 @@ private module Cached { } cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - - cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { - exists(TranslatedExpr translatedExpr | - translatedExpr = getTranslatedExpr(result) and - instruction = translatedExpr.getResult() and - // Only associate `instruction` with this expression if the translated - // expression actually produced the instruction; not if it merely - // forwarded the result of another translated expression. - instruction = translatedExpr.getInstruction(_) - ) - } - - cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getInstructionConvertedResultExpression(instruction).getUnconverted() - } - - cached - Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) - } - - cached - Instruction getMemoryOperandDefinition( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) and - overlap instanceof MustTotallyOverlap - } - - /** Gets a non-phi instruction that defines an operand of `instr`. */ - private Instruction getNonPhiOperandDef(Instruction instr) { - result = getRegisterOperandDefinition(instr, _) - or - result = getMemoryOperandDefinition(instr, _, _) - } - - /** - * Gets a non-phi instruction that defines an operand of `instr` but only if - * both `instr` and the result have neighbor on the other side of the edge - * between them. This is a necessary condition for being in a cycle, and it - * removes about two thirds of the tuples that would otherwise be in this - * predicate. - */ - private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { - result = getNonPhiOperandDef(instr) and - exists(getNonPhiOperandDef(result)) and - instr = getNonPhiOperandDef(_) - } - - /** - * Holds if `instr` is part of a cycle in the operand graph that doesn't go - * through a phi instruction and therefore should be impossible. - * - * If such cycles are present, either due to a programming error in the IR - * generation or due to a malformed database, it can cause infinite loops in - * analyses that assume a cycle-free graph of non-phi operands. Therefore it's - * better to remove these operands than to leave cycles in the operand graph. - */ - pragma[noopt] - cached - predicate isInCycle(Instruction instr) { - instr instanceof Instruction and - getNonPhiOperandDefOfIntermediate+(instr) = instr - } - - cached - CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { - // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as - // the result type of the load. - result = instruction.(LoadInstruction).getResultLanguageType() - or - not instruction instanceof LoadInstruction and - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperandType(getInstructionTag(instruction), tag) - } - - cached - Instruction getPhiOperandDefinition( - PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap - ) { - none() - } - - cached - Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } - - cached - Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionSuccessor(getInstructionTag(instruction), kind) - } - - /** - * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> - * `targetInstruction` is a back edge under the condition that - * `requiredAncestor` is an ancestor of `sourceElement`. - */ - private predicate backEdgeCandidate( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, - Instruction targetInstruction, EdgeKind kind - ) { - // While loop: - // Any edge from within the body of the loop to the condition of the loop - // is a back edge. This includes edges from `continue` and the fall-through - // edge(s) after the last instruction(s) in the body. - exists(TranslatedWhileStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getBody() - ) - or - // Do-while loop: - // The back edge should be the edge(s) from the condition to the - // body. This ensures that it's the back edge that will be pruned in a `do - // { ... } while (0)` statement. Note that all `continue` statements in a - // do-while loop produce forward edges. - exists(TranslatedDoStmt s | - targetInstruction = s.getBody().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getCondition() - ) - or - // For loop: - // Any edge from within the body or update of the loop to the condition of - // the loop is a back edge. When there is no loop update expression, this - // includes edges from `continue` and the fall-through edge(s) after the - // last instruction(s) in the body. A for loop may not have a condition, in - // which case `getFirstConditionInstruction` returns the body instead. - exists(TranslatedForStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - ( - requiredAncestor = s.getUpdate() - or - not exists(s.getUpdate()) and - requiredAncestor = s.getBody() - ) - ) - or - // Range-based for loop: - // Any edge from within the update of the loop to the condition of - // the loop is a back edge. - exists(TranslatedRangeBasedForStmt s | - targetInstruction = s.getCondition().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getUpdate() - ) - } - - private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { - backEdgeCandidate(jumpSource, _, _, _, _) and - ancestor = jumpSource - or - // For performance, we don't want a fastTC here - jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) - } - - cached - Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { - exists( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor - | - backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and - jumpSourceHasAncestor(sourceElement, requiredAncestor) and - instruction = sourceElement.getInstruction(sourceTag) - ) - or - // Goto statement: - // As a conservative approximation, any edge out of `goto` is a back edge - // unless it goes strictly forward in the program text. A `goto` whose - // source and target are both inside a macro will be seen as having the - // same location for source and target, so we conservatively assume that - // such a `goto` creates a back edge. - exists(TranslatedElement s, GotoStmt goto | - not isStrictlyForwardGoto(goto) and - goto = s.getAST() and - exists(InstructionTag tag | - result = s.getInstructionSuccessor(tag, kind) and - instruction = s.getInstruction(tag) - ) - ) - } - - /** Holds if `goto` jumps strictly forward in the program text. */ - private predicate isStrictlyForwardGoto(GotoStmt goto) { - goto.getLocation().isBefore(goto.getTarget().getLocation()) - } - - cached - Locatable getInstructionAST(Instruction instruction) { - result = getInstructionTranslatedElement(instruction).getAST() - } - - cached - CppType getInstructionResultType(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), result) - } - - cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { + TIRVariable getInstructionVariable(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | element = getInstructionTranslatedElement(instruction) and tag = getInstructionTag(instruction) and @@ -301,10 +82,9 @@ private module Cached { cached Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionField(getInstructionTag(instruction)) } cached @@ -323,10 +103,9 @@ private module Cached { cached int getInstructionIndex(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionIndex(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionIndex(getInstructionTag(instruction)) } cached @@ -349,20 +128,11 @@ private module Cached { .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) } - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - cached int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionElementSize(getInstructionTag(instruction)) } cached @@ -371,22 +141,225 @@ private module Cached { } cached - int getInstructionResultSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionResultSize(tag) + Expr getInstructionConvertedResultExpression(Instruction instruction) { + exists(TranslatedExpr translatedExpr | + translatedExpr = getTranslatedExpr(result) and + instruction = translatedExpr.getResult() and + // Only associate `instruction` with this expression if the translated + // expression actually produced the instruction; not if it merely + // forwarded the result of another translated expression. + instruction = translatedExpr.getInstruction(_) ) } cached - Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getPrimaryInstructionForSideEffect(tag) - ) + Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + result = getInstructionConvertedResultExpression(instruction).getUnconverted() } } +class TStageInstruction = TRawInstruction; + +predicate hasInstruction(TRawInstruction instr) { any() } + +predicate hasModeledMemoryResult(Instruction instruction) { none() } + +predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal +} + +Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionRegisterOperand(getInstructionTag(instruction), tag) +} + +Instruction getMemoryOperandDefinition( + Instruction instruction, MemoryOperandTag tag, Overlap overlap +) { + none() +} + +/** Gets a non-phi instruction that defines an operand of `instr`. */ +private Instruction getNonPhiOperandDef(Instruction instr) { + result = getRegisterOperandDefinition(instr, _) + or + result = getMemoryOperandDefinition(instr, _, _) +} + +/** + * Gets a non-phi instruction that defines an operand of `instr` but only if + * both `instr` and the result have neighbor on the other side of the edge + * between them. This is a necessary condition for being in a cycle, and it + * removes about two thirds of the tuples that would otherwise be in this + * predicate. + */ +private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { + result = getNonPhiOperandDef(instr) and + exists(getNonPhiOperandDef(result)) and + instr = getNonPhiOperandDef(_) +} + +/** + * Holds if `instr` is part of a cycle in the operand graph that doesn't go + * through a phi instruction and therefore should be impossible. + * + * If such cycles are present, either due to a programming error in the IR + * generation or due to a malformed database, it can cause infinite loops in + * analyses that assume a cycle-free graph of non-phi operands. Therefore it's + * better to remove these operands than to leave cycles in the operand graph. + */ +pragma[noopt] +predicate isInCycle(Instruction instr) { + instr instanceof Instruction and + getNonPhiOperandDefOfIntermediate+(instr) = instr +} + +CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as + // the result type of the load. + tag instanceof LoadOperandTag and + result = instruction.(LoadInstruction).getResultLanguageType() + or + not instruction instanceof LoadInstruction and + result = + getInstructionTranslatedElement(instruction) + .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) +} + +Instruction getPhiOperandDefinition( + PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap +) { + none() +} + +Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } + +Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionSuccessor(getInstructionTag(instruction), kind) +} + +/** + * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> + * `targetInstruction` is a back edge under the condition that + * `requiredAncestor` is an ancestor of `sourceElement`. + */ +private predicate backEdgeCandidate( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, + Instruction targetInstruction, EdgeKind kind +) { + // While loop: + // Any edge from within the body of the loop to the condition of the loop + // is a back edge. This includes edges from `continue` and the fall-through + // edge(s) after the last instruction(s) in the body. + exists(TranslatedWhileStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getBody() + ) + or + // Do-while loop: + // The back edge should be the edge(s) from the condition to the + // body. This ensures that it's the back edge that will be pruned in a `do + // { ... } while (0)` statement. Note that all `continue` statements in a + // do-while loop produce forward edges. + exists(TranslatedDoStmt s | + targetInstruction = s.getBody().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getCondition() + ) + or + // For loop: + // Any edge from within the body or update of the loop to the condition of + // the loop is a back edge. When there is no loop update expression, this + // includes edges from `continue` and the fall-through edge(s) after the + // last instruction(s) in the body. A for loop may not have a condition, in + // which case `getFirstConditionInstruction` returns the body instead. + exists(TranslatedForStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + ( + requiredAncestor = s.getUpdate() + or + not exists(s.getUpdate()) and + requiredAncestor = s.getBody() + ) + ) + or + // Range-based for loop: + // Any edge from within the update of the loop to the condition of + // the loop is a back edge. + exists(TranslatedRangeBasedForStmt s | + targetInstruction = s.getCondition().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getUpdate() + ) +} + +private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { + backEdgeCandidate(jumpSource, _, _, _, _) and + ancestor = jumpSource + or + // For performance, we don't want a fastTC here + jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) +} + +Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { + exists( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor + | + backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and + jumpSourceHasAncestor(sourceElement, requiredAncestor) and + instruction = sourceElement.getInstruction(sourceTag) + ) + or + // Goto statement: + // As a conservative approximation, any edge out of `goto` is a back edge + // unless it goes strictly forward in the program text. A `goto` whose + // source and target are both inside a macro will be seen as having the + // same location for source and target, so we conservatively assume that + // such a `goto` creates a back edge. + exists(TranslatedElement s, GotoStmt goto | + not isStrictlyForwardGoto(goto) and + goto = s.getAST() and + exists(InstructionTag tag | + result = s.getInstructionSuccessor(tag, kind) and + instruction = s.getInstruction(tag) + ) + ) +} + +/** Holds if `goto` jumps strictly forward in the program text. */ +private predicate isStrictlyForwardGoto(GotoStmt goto) { + goto.getLocation().isBefore(goto.getTarget().getLocation()) +} + +Locatable getInstructionAST(TStageInstruction instr) { + result = getInstructionTranslatedElement(instr).getAST() +} + +CppType getInstructionResultType(TStageInstruction instr) { + getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result) +} + +Opcode getInstructionOpcode(TStageInstruction instr) { + getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _) +} + +IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() +} + +Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getPrimaryInstructionForSideEffect(getInstructionTag(instruction)) +} + import CachedForDebugging cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll index 8fd2f662f34..82cc38ac092 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import IRConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index 4ddef00ee7b..122a23b76a0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -2,7 +2,6 @@ private import cpp newtype TInstructionTag = OnlyInstructionTag() or // Single instruction (not including implicit Load) - InitializeThisTag() or InitializerVariableAddressTag() or InitializerLoadStringTag() or InitializerStoreTag() or @@ -28,8 +27,6 @@ newtype TInstructionTag = ReturnValueAddressTag() or ReturnTag() or ExitFunctionTag() or - UnmodeledDefinitionTag() or - UnmodeledUseTag() or AliasedDefinitionTag() or InitializeNonLocalTag() or AliasedUseTag() or @@ -72,7 +69,9 @@ newtype TInstructionTag = VarArgsMoveNextTag() or VarArgsVAListStoreTag() or AsmTag() or - AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } + AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } or + ThisAddressTag() or + ThisLoadTag() class InstructionTag extends TInstructionTag { final string toString() { result = "Tag" } @@ -127,10 +126,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = ExitFunctionTag() and result = "ExitFunc" or - tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" - or - tag = UnmodeledUseTag() and result = "UnmodeledUse" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = InitializeNonLocalTag() and result = "InitNonLocal" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 22f104e12c8..821bf94709a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -94,7 +94,7 @@ abstract class TranslatedCall extends TranslatedExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = CallTag() and ( operandTag instanceof CallTargetOperandTag and @@ -108,14 +108,11 @@ abstract class TranslatedCall extends TranslatedExpr { result = getArgument(argTag.getArgIndex()).getResult() ) ) - or - tag = CallSideEffectTag() and - hasSideEffect() and - operandTag instanceof SideEffectOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = CallSideEffectTag() and hasSideEffect() and operandTag instanceof SideEffectOperandTag and @@ -375,13 +372,13 @@ class TranslatedAllocationSideEffects extends TranslatedSideEffects, override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - kind = gotoEdge() and + kind = EdgeKind::gotoEdge() and if exists(getChild(0)) then result = getChild(0).getFirstInstruction() else result = getParent().getChildSuccessor(this) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag = addressOperand() and result = getPrimaryInstructionForSideEffect(OnlyInstructionTag()) @@ -437,7 +434,7 @@ class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof AddressOperandTag and result = getParent().(TranslatedStructorCall).getQualifierResult() @@ -513,17 +510,12 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff kind instanceof GotoEdge } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof AddressOperandTag and result = getTranslatedExpr(arg).getResult() or tag instanceof OnlyInstructionTag and - operandTag instanceof SideEffectOperandTag and - not isWrite() and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() - or - tag instanceof OnlyInstructionTag and operandTag instanceof BufferSizeOperandTag and result = getTranslatedExpr(call @@ -531,7 +523,8 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff .getFullyConverted()).getResult() } - override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) { + not isWrite() and if hasSpecificReadSideEffect(any(BufferAccessOpcode op)) then result = getUnknownType() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll index e2fc86db7ce..0779d6fbda5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -182,7 +182,7 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ValueConditionConditionalBranchTag() and operandTag instanceof ConditionOperandTag and result = getValueExpr().getResult() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 6cc7fd7853f..de63b81c876 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -181,14 +181,11 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio tag = DynamicInitializationFlagConstantTag() and result = "1" } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = DynamicInitializationFlagLoadTag() and ( operandTag instanceof AddressOperandTag and result = getInstruction(DynamicInitializationFlagAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(var.getFunction()).getUnmodeledDefinitionInstruction() ) or tag = DynamicInitializationConditionalBranchTag() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index ab354a3dca1..f3c8816c19d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -24,6 +24,16 @@ private Element getRealParent(Expr expr) { result.(Destructor).getADestruction() = expr } +IRUserVariable getIRUserVariable(Function func, Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + /** * Holds if `expr` is a constant of a type that can be replaced directly with * its value in the IR. This does not include address constants as we have no @@ -400,6 +410,9 @@ newtype TTranslatedElement = TTranslatedConstructorInitList(Function func) { translateFunction(func) } or // A destructor destruction list TTranslatedDestructorDestructionList(Function func) { translateFunction(func) } or + TTranslatedThisParameter(Function func) { + translateFunction(func) and func.isMember() and not func.isStatic() + } or // A function parameter TTranslatedParameter(Parameter param) { exists(Function func | @@ -412,8 +425,11 @@ newtype TTranslatedElement = } or TTranslatedEllipsisParameter(Function func) { translateFunction(func) and func.isVarargs() } or TTranslatedReadEffects(Function func) { translateFunction(func) } or + TTranslatedThisReadEffect(Function func) { + translateFunction(func) and func.isMember() and not func.isStatic() + } or // The read side effects in a function's return block - TTranslatedReadEffect(Parameter param) { + TTranslatedParameterReadEffect(Parameter param) { translateFunction(param.getFunction()) and exists(Type t | t = param.getUnspecifiedType() | t instanceof ArrayType or @@ -460,7 +476,7 @@ newtype TTranslatedElement = ) } or // The side effects of an allocation, i.e. `new`, `new[]` or `malloc` - TTranslatedAllocationSideEffects(AllocationExpr expr) or + TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or // A precise side effect of an argument to a `Call` TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( @@ -699,12 +715,8 @@ abstract class TranslatedElement extends TTranslatedElement { int getInstructionElementSize(InstructionTag tag) { none() } /** - * If the instruction specified by `tag` has a result of type `UnknownType`, - * gets the size of the result in bytes. If the result does not have a knonwn - * constant size, this predicate does not hold. + * Holds if the generated IR refers to an opaque type with size `byteSize`. */ - int getInstructionResultSize(InstructionTag tag) { none() } - predicate needsUnknownOpaqueType(int byteSize) { none() } /** @@ -736,12 +748,12 @@ abstract class TranslatedElement extends TTranslatedElement { * Gets the instruction whose result is consumed as an operand of the * instruction specified by `tag`, with the operand specified by `operandTag`. */ - Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } /** * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. */ - CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } + CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } /** * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 1d305ce46d0..98bcd1da8b2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -183,7 +183,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ConditionValueTrueStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -206,9 +206,6 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ( operandTag instanceof AddressOperandTag and result = getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -282,14 +279,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override Instruction getResult() { result = getInstruction(LoadTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = LoadTag() and ( operandTag instanceof AddressOperandTag and result = getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -332,7 +326,7 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy { override Instruction getResult() { result = getInstruction(ResultCopyTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ResultCopyTag() and operandTag instanceof UnaryOperandTag and result = getOperand().getResult() @@ -369,7 +363,9 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr { none() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } private TranslatedExpr getLeftOperand() { result = getTranslatedExpr(expr.getLeftOperand().getFullyConverted()) @@ -429,7 +425,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { resultType = getTypeForPRValue(expr.getType()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = CrementOpTag() and ( operandTag instanceof LeftOperandTag and @@ -580,7 +576,7 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { resultType = getTypeForGLValue(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and ( operandTag instanceof LeftOperandTag and @@ -622,7 +618,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr { final override Instruction getResult() { result = getOperand().getResult() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -668,31 +664,40 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override TranslatedElement getChild(int id) { none() } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::CopyValue and + tag = ThisAddressTag() and + opcode instanceof Opcode::VariableAddress and + resultType = getTypeForGLValue(any(UnknownType t)) + or + tag = ThisLoadTag() and + opcode instanceof Opcode::Load and resultType = getResultType() } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = getInstruction(ThisLoadTag()) } - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { result = getInstruction(ThisAddressTag()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and - tag = OnlyInstructionTag() and + tag = ThisAddressTag() and + result = getInstruction(ThisLoadTag()) + or + kind instanceof GotoEdge and + tag = ThisLoadTag() and result = getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { none() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag instanceof UnaryOperandTag and - result = getInitializeThisInstruction() + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = ThisLoadTag() and + operandTag instanceof AddressOperandTag and + result = getInstruction(ThisAddressTag()) } - private Instruction getInitializeThisInstruction() { - result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction() + override IRVariable getInstructionVariable(InstructionTag tag) { + tag = ThisAddressTag() and + result = this.getEnclosingFunction().getThisVariable() } } @@ -729,7 +734,9 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { else result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and @@ -748,7 +755,7 @@ class TranslatedFieldAccess extends TranslatedVariableAccess { override Instruction getFirstInstruction() { result = getQualifier().getFirstInstruction() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getQualifier().getResult() @@ -822,7 +829,7 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -906,7 +913,7 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and result = getOperand().getResult() and operandTag instanceof UnaryOperandTag @@ -960,7 +967,7 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getOperand().getResult() @@ -1004,7 +1011,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion { if resultType instanceof PointerType then if resultType.(PointerType).getBaseType() instanceof VoidType - then result instanceof Opcode::DynamicCastToVoid + then result instanceof Opcode::CompleteObjectAddress else result instanceof Opcode::CheckedConvertOrNull else result instanceof Opcode::CheckedConvertOrThrow ) @@ -1070,7 +1077,7 @@ class TranslatedBoolConversion extends TranslatedConversion { override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = BoolConversionCompareTag() and ( operandTag instanceof LeftOperandTag and @@ -1172,7 +1179,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { id = 1 and result = getRightOperand() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and if swapOperandsOnOp() then ( @@ -1306,7 +1313,7 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { resultType = getTypeForPRValue(expr.getType()) // Always a prvalue } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = AssignmentStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -1482,7 +1489,7 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { result = getElementSize(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { leftOperandNeedsConversion() and tag = AssignOperationConvertLeftTag() and operandTag instanceof UnaryOperandTag and @@ -1626,7 +1633,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { result = expr.getAllocatedElementType().getSize().toString() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = AllocationSizeTag() and ( operandTag instanceof LeftOperandTag and result = getInstruction(AllocationExtentConvertTag()) @@ -1691,7 +1698,8 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect else if index = 1 and expr.hasAlignedAllocation() then result = getTranslatedExpr(expr.getAlignmentArgument()) - else result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index)) + else + result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted()) } } @@ -1742,7 +1750,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction() @@ -1832,7 +1840,7 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { not resultIsVoid() and ( not thenIsVoid() and @@ -1859,9 +1867,6 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { ( operandTag instanceof AddressOperandTag and result = getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) ) } @@ -2014,8 +2019,8 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = super.getInstructionRegisterOperand(tag, operandTag) or tag = ValueConditionConditionalBranchTag() and operandTag instanceof ConditionOperandTag and @@ -2093,20 +2098,19 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn type = getTypeForPRValue(getExceptionType()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedVariableInitialization.super.getInstructionOperand(tag, operandTag) + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedVariableInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = ThrowTag() and ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and result = getTypeForPRValue(getExceptionType()) @@ -2191,7 +2195,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr { resultType = getResultType() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and exists(int index | operandTag = positionalArgumentOperand(index) and @@ -2311,7 +2315,7 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr { result = getEnclosingFunction().getEllipsisVariable() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsStartTag() and operandTag instanceof UnaryOperandTag and result = getInstruction(VarArgsStartEllipsisAddressTag()) @@ -2382,14 +2386,11 @@ class TranslatedVarArg extends TranslatedNonConstantExpr { result = getInstruction(VarArgsVAListLoadTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and result = getVAList().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = VarArgsArgAddressTag() and @@ -2442,7 +2443,7 @@ class TranslatedVarArgsEnd extends TranslatedNonConstantExpr { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getVAList().getResult() @@ -2503,14 +2504,11 @@ class TranslatedVarArgCopy extends TranslatedNonConstantExpr { result = getInstruction(VarArgsVAListStoreTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and result = getSourceVAList().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = VarArgsVAListStoreTag() and @@ -2560,7 +2558,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In child = getInitialization() and result = getParent().getChildSuccessor(this) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getAllocatorCall().getResult() @@ -2623,7 +2621,7 @@ class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionEx child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -2657,7 +2655,7 @@ class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr { child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -2761,7 +2759,7 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont resultType = getTypeForPRValue(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) @@ -2770,9 +2768,6 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -2832,7 +2827,7 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr { override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof UnaryOperandTag and result = getTranslatedExpr(expr.getResultExpr().getFullyConverted()).getResult() @@ -2856,7 +2851,7 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr { final override Instruction getChildSuccessor(TranslatedElement child) { none() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 67b9622c3be..f55d661b202 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -73,15 +73,15 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final override Function getFunction() { result = func } final override TranslatedElement getChild(int id) { - id = -4 and result = getReadEffects() + id = -5 and result = getReadEffects() or - id = -3 and result = getConstructorInitList() + id = -4 and result = getConstructorInitList() or - id = -2 and result = getBody() + id = -3 and result = getBody() or - id = -1 and result = getDestructorDestructionList() + id = -2 and result = getDestructorDestructionList() or - id >= 0 and result = getParameter(id) + id >= -1 and result = getParameter(id) } final private TranslatedConstructorInitList getConstructorInitList() { @@ -97,6 +97,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final private TranslatedReadEffects getReadEffects() { result = getTranslatedReadEffects(func) } final private TranslatedParameter getParameter(int index) { + result = getTranslatedThisParameter(func) and + index = -1 + or result = getTranslatedParameter(func.getParameter(index)) or index = getEllipsisParameterIndexForFunction(func) and @@ -114,36 +117,23 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = AliasedDefinitionTag() and result = getInstruction(InitializeNonLocalTag()) or - tag = InitializeNonLocalTag() and - result = getInstruction(UnmodeledDefinitionTag()) - or ( - tag = UnmodeledDefinitionTag() and + tag = InitializeNonLocalTag() and if exists(getThisType()) - then result = getInstruction(InitializeThisTag()) + then result = getParameter(-1).getFirstInstruction() else if exists(getParameter(0)) then result = getParameter(0).getFirstInstruction() else result = getBody().getFirstInstruction() ) or - ( - tag = InitializeThisTag() and - if exists(getParameter(0)) - then result = getParameter(0).getFirstInstruction() - else result = getConstructorInitList().getFirstInstruction() - ) - or tag = ReturnValueAddressTag() and result = getInstruction(ReturnTag()) or tag = ReturnTag() and - result = getInstruction(UnmodeledUseTag()) + result = getInstruction(AliasedUseTag()) or tag = UnwindTag() and - result = getInstruction(UnmodeledUseTag()) - or - tag = UnmodeledUseTag() and result = getInstruction(AliasedUseTag()) or tag = AliasedUseTag() and @@ -182,10 +172,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::EnterFunction and resultType = getVoidType() or - tag = UnmodeledDefinitionTag() and - opcode instanceof Opcode::UnmodeledDefinition and - resultType = getUnknownType() - or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and resultType = getUnknownType() @@ -194,10 +180,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::InitializeNonLocal and resultType = getUnknownType() or - tag = InitializeThisTag() and - opcode instanceof Opcode::InitializeThis and - resultType = getTypeForGLValue(getThisType()) - or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and resultType = getTypeForGLValue(getReturnType()) and @@ -221,10 +203,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { exists(ThrowExpr throw | throw.getEnclosingFunction() = func) ) or - tag = UnmodeledUseTag() and - opcode instanceof Opcode::UnmodeledUse and - resultType = getVoidType() - or tag = AliasedUseTag() and opcode instanceof Opcode::AliasedUse and resultType = getVoidType() @@ -239,32 +217,16 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getInstruction(UnwindTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result.getEnclosingFunction() = func and - result.hasMemoryResult() - or - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result = getUnmodeledDefinitionInstruction() - or - tag = AliasedUseTag() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() - or + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ReturnTag() and hasReturnValue() and - ( - operandTag instanceof AddressOperandTag and - result = getInstruction(ReturnValueAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = getInstruction(ReturnValueAddressTag()) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = ReturnTag() and hasReturnValue() and operandTag instanceof LoadOperandTag and @@ -292,6 +254,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = EllipsisTempVar() and func.isVarargs() and type = getEllipsisVariablePRValueType() + or + tag = ThisTempVar() and + type = getTypeForGLValue(getThisType()) } /** @@ -314,23 +279,23 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { */ final IREllipsisVariable getEllipsisVariable() { result.getEnclosingFunction() = func } + /** + * Gets the variable that represents the `this` pointer for this function, if any. + */ + final IRThisVariable getThisVariable() { result = getIRTempVariable(func, ThisTempVar()) } + /** * Holds if the function has a non-`void` return type. */ final predicate hasReturnValue() { hasReturnValue(func) } - /** - * Gets the single `UnmodeledDefinition` instruction for this function. - */ - final Instruction getUnmodeledDefinitionInstruction() { - result = getInstruction(UnmodeledDefinitionTag()) - } - /** * Gets the single `InitializeThis` instruction for this function. Holds only * if the function is an instance member function, constructor, or destructor. */ - final Instruction getInitializeThisInstruction() { result = getInstruction(InitializeThisTag()) } + final Instruction getInitializeThisInstruction() { + result = getTranslatedThisParameter(func).getInstruction(InitializerStoreTag()) + } /** * Gets the type pointed to by the `this` pointer for this function (i.e. `*this`). @@ -371,6 +336,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final Type getReturnType() { result = func.getType() } } +/** + * Gets the `TranslatedThisParameter` for function `func`, if one exists. + */ +TranslatedThisParameter getTranslatedThisParameter(Function func) { result.getFunction() = func } + /** * Gets the `TranslatedPositionalParameter` that represents parameter `param`. */ @@ -385,8 +355,9 @@ TranslatedEllipsisParameter getTranslatedEllipsisParameter(Function func) { /** * The IR translation of a parameter to a function. This can be either a user-declared parameter - * (`TranslatedPositionParameter`) or the synthesized parameter used to represent a `...` in a - * varargs function (`TranslatedEllipsisParameter`). + * (`TranslatedPositionParameter`), the synthesized parameter used to represent `this`, or the + * synthesized parameter used to represent a `...` in a varargs function + * (`TranslatedEllipsisParameter`). */ abstract class TranslatedParameter extends TranslatedElement { final override TranslatedElement getChild(int id) { none() } @@ -433,7 +404,7 @@ abstract class TranslatedParameter extends TranslatedElement { hasIndirection() and tag = InitializerIndirectStoreTag() and opcode instanceof Opcode::InitializeIndirection and - resultType = getUnknownType() + resultType = getInitializationResultType() } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -445,7 +416,7 @@ abstract class TranslatedParameter extends TranslatedElement { result = getIRVariable() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -457,9 +428,6 @@ abstract class TranslatedParameter extends TranslatedElement { ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() ) or tag = InitializerIndirectStoreTag() and @@ -473,9 +441,43 @@ abstract class TranslatedParameter extends TranslatedElement { abstract CppType getPRValueType(); + abstract CppType getInitializationResultType(); + abstract IRAutomaticVariable getIRVariable(); } +/** + * The IR translation of the synthesized parameter used to represent the `...` in a varargs + * function. + */ +class TranslatedThisParameter extends TranslatedParameter, TTranslatedThisParameter { + Function func; + + TranslatedThisParameter() { this = TTranslatedThisParameter(func) } + + final override string toString() { result = "this" } + + final override Locatable getAST() { result = func } + + final override Function getFunction() { result = func } + + final override predicate hasIndirection() { any() } + + final override CppType getGLValueType() { result = getTypeForGLValue(any(UnknownType t)) } + + final override CppType getPRValueType() { + result = getTypeForGLValue(getTranslatedFunction(func).getThisType()) + } + + final override CppType getInitializationResultType() { + result = getTypeForPRValue(getTranslatedFunction(func).getThisType()) + } + + final override IRThisVariable getIRVariable() { + result = getTranslatedFunction(func).getThisVariable() + } +} + /** * Represents the IR translation of a function parameter, including the * initialization of that parameter with the incoming argument. @@ -506,6 +508,8 @@ class TranslatedPositionalParameter extends TranslatedParameter, TTranslatedPara final override CppType getPRValueType() { result = getTypeForPRValue(getVariableType(param)) } + final override CppType getInitializationResultType() { result = getUnknownType() } + final override IRAutomaticUserVariable getIRVariable() { result = getIRUserVariable(getFunction(), param) } @@ -532,6 +536,8 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips final override CppType getPRValueType() { result = getEllipsisVariablePRValueType() } + final override CppType getInitializationResultType() { result = getUnknownType() } + final override IREllipsisVariable getIRVariable() { result = getTranslatedFunction(func).getEllipsisVariable() } @@ -670,14 +676,17 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override string toString() { result = "read effects: " + func.toString() } override TranslatedElement getChild(int id) { - result = getTranslatedReadEffect(func.getParameter(id)) + result = getTranslatedThisReadEffect(func) and + id = -1 + or + result = getTranslatedParameterReadEffect(func.getParameter(id)) } override Instruction getFirstInstruction() { if exists(getAChild()) then result = - min(TranslatedReadEffect child, int id | child = getChild(id) | child order by id) + min(TranslatedElement child, int id | child = getChild(id) | child order by id) .getFirstInstruction() else result = getParent().getChildSuccessor(this) } @@ -703,52 +712,81 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } } -private TranslatedReadEffect getTranslatedReadEffect(Parameter param) { result.getAST() = param } +private TranslatedThisReadEffect getTranslatedThisReadEffect(Function func) { + result.getAST() = func +} -class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { - Parameter param; - - TranslatedReadEffect() { this = TTranslatedReadEffect(param) } - - override Locatable getAST() { result = param } - - override string toString() { result = "read effect: " + param.toString() } +private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) { + result.getAST() = param +} +abstract class TranslatedReadEffect extends TranslatedElement { override TranslatedElement getChild(int id) { none() } override Instruction getChildSuccessor(TranslatedElement child) { none() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind edge) { tag = OnlyInstructionTag() and - edge = gotoEdge() and + edge = EdgeKind::gotoEdge() and result = getParent().getChildSuccessor(this) } override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override Function getFunction() { result = param.getFunction() } - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::ReturnIndirection and tag = OnlyInstructionTag() and resultType = getVoidType() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag = sideEffectOperand() and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() - or - tag = OnlyInstructionTag() and - operandTag = addressOperand() and - result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) - } - - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = OnlyInstructionTag() and operandTag = sideEffectOperand() and result = getUnknownType() } +} + +class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisReadEffect { + Function func; + + TranslatedThisReadEffect() { this = TTranslatedThisReadEffect(func) } + + override Locatable getAST() { result = func } + + override Function getFunction() { result = func } + + override string toString() { result = "read effect: this" } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedThisParameter(func).getInstruction(InitializerIndirectAddressTag()) + } + + final override IRVariable getInstructionVariable(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = getTranslatedFunction(func).getThisVariable() + } +} + +class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedParameterReadEffect { + Parameter param; + + TranslatedParameterReadEffect() { this = TTranslatedParameterReadEffect(param) } + + override Locatable getAST() { result = param } + + override string toString() { result = "read effect: " + param.toString() } + + override Function getFunction() { result = param.getFunction() } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) + } final override IRVariable getInstructionVariable(InstructionTag tag) { tag = OnlyInstructionTag() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 5ca04d91a05..4b6538654db 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -75,7 +75,7 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi child = getInitialization() and result = getInitializationSuccessor() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { hasUninitializedInstruction() and tag = InitializerStoreTag() and operandTag instanceof AddressOperandTag and @@ -262,7 +262,7 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio child = getInitializer() and result = getInstruction(InitializerStoreTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -355,14 +355,11 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati child = getInitializer() and result = getInstruction(InitializerLoadStringTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerLoadStringTag() and ( operandTag instanceof AddressOperandTag and result = getInitializer().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = InitializerStoreTag() and @@ -418,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati ) } - override int getInstructionResultSize(InstructionTag tag) { - exists(int elementCount | - zeroInitRange(_, elementCount) and - ( - tag = ZeroPadStringConstantTag() or - tag = ZeroPadStringStoreTag() - ) and - result = elementCount * getElementType().getSize() - ) - } - private Type getElementType() { result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType() } @@ -461,7 +447,9 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization child = getInitializer() and result = getParent().getChildSuccessor(this) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } override Instruction getReceiver() { result = getContext().getTargetAddress() } } @@ -508,7 +496,7 @@ abstract class TranslatedFieldInitialization extends TranslatedElement { resultType = getTypeForGLValue(field.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = getFieldAddressTag() and operandTag instanceof UnaryOperandTag and result = getParent().(InitializationContext).getTargetAddress() @@ -599,8 +587,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization, result = getZeroValue(field.getUnspecifiedType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedFieldInitialization.super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = getFieldDefaultValueStoreTag() and ( @@ -656,7 +644,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement { kind instanceof GotoEdge } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = getElementAddressTag() and ( operandTag instanceof LeftOperandTag and @@ -773,17 +761,8 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati result = getZeroValue(getElementType()) } - override int getInstructionResultSize(InstructionTag tag) { - elementCount > 1 and - ( - tag = getElementDefaultValueTag() or - tag = getElementDefaultValueStoreTag() - ) and - result = elementCount * getElementType().getSize() - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedElementInitialization.super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = getElementDefaultValueStoreTag() and ( @@ -861,7 +840,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru final override Instruction getReceiver() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getTranslatedFunction(getFunction()).getInitializeThisInstruction() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index a4c9d487437..3339046d391 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -713,7 +713,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { resultType = getVoidType() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = SwitchBranchTag() and operandTag instanceof ConditionOperandTag and result = getExpr().getResult() @@ -759,11 +759,7 @@ class TranslatedAsmStmt extends TranslatedStmt { resultType = getUnknownType() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = AsmTag() and - operandTag instanceof SideEffectOperandTag and - result = getTranslatedFunction(stmt.getEnclosingFunction()).getUnmodeledDefinitionInstruction() - or + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { exists(int index | tag = AsmTag() and operandTag = asmOperand(index) and @@ -771,7 +767,9 @@ class TranslatedAsmStmt extends TranslatedStmt { ) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = AsmTag() and operandTag instanceof SideEffectOperandTag and result = getUnknownType() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index badd48552a5..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index dce1717bdc9..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,49 +20,89 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -70,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -91,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -206,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..909a7a5fc24 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll new file mode 100644 index 00000000000..6a87b9b4b5f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(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) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + 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, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * 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, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * 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, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + 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 + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 1e9c2d1d913..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ @@ -40,16 +28,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql deleted file mode 100644 index eee45030caf..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ssa-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -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 Imports::Overlap - 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 a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * 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()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 0d5e7fe595c..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,10 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } +} + +/** + * A temporary variable generated to hold the `this` pointer. + */ +class IRThisVariable extends IRTempVariable, IRParameter { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -240,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -257,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -265,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 780f636ff10..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -320,8 +343,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -393,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -408,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -475,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -497,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -506,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -542,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is true. + */ + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -635,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -779,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -858,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -868,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -878,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -888,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -898,16 +1466,33 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + /** Gets the successor instruction along the default edge of the switch, if any. */ + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -937,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -982,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -997,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1047,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1057,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1088,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1104,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1112,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1119,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1212,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1230,10 +1854,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ @@ -1248,12 +1868,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * @@ -1351,26 +1965,33 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1383,3 +2004,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 1836f4c4b2f..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -14,16 +18,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -31,14 +27,72 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the register operand with the specified parameters. + */ +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the non-Phi memory operand with the specified parameters. + */ +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) +} + +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); +} + +/** + * Returns the Phi operand with the specified parameters. + */ +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -104,7 +158,17 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** @@ -169,8 +233,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,30 +268,37 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { result = defInstr } final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. @@ -235,15 +306,33 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +/** + * A memory operand other than the operand of a `Phi` instruction. + */ +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } - final override Overlap getDefinitionOverlap() { result = overlap } + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -258,8 +347,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +355,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +363,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +370,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +377,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +384,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +391,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +398,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } -} - -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } } /** @@ -342,8 +405,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +422,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +429,30 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -427,8 +482,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -438,7 +491,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -47,7 +58,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +235,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..796fb792366 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" + this instanceof TConstantValueNumber and result = "Constant" or this instanceof TStringConstantValueNumber and result = "StringConstant" or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..19fb0490f80 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and @@ -247,6 +248,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 4cc52d3bbf9..3a7a08accc0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..25f9d5d454a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/unaliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 155934689b6..ae0e03e97da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,47 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -67,15 +66,13 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -83,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -127,40 +124,13 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap @@ -201,13 +171,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -220,7 +192,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -232,21 +204,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -257,20 +219,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -289,137 +251,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() + or + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + instr = unreachedInstruction(_) and result = Language::getVoidType() + } + + cached + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() + or + instr = phiInstruction(_, _) and result instanceof Opcode::Phi + or + instr = chiInstruction(_) and result instanceof Opcode::Chi + or + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached + } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() + or + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(_) and - result = Language::getVoidType() - } - - cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) or - instruction instanceof Chi and - result instanceof Opcode::Chi - or - instruction instanceof Phi and - result instanceof Opcode::Phi - or - instruction instanceof Unreached and - result instanceof Opcode::Unreached - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) - or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) - or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) + instr = unreachedInstruction(result) } cached @@ -430,7 +328,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -438,6 +336,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -617,7 +523,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -636,7 +542,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -920,7 +826,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -930,7 +836,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -941,7 +847,10 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -954,6 +863,9 @@ module SSASanity { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -962,4 +874,41 @@ module SSASanity { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } +} + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29..f347df86ba1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 4cfbdfe831e..73b08d1286b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage +import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 1b5ee80b603..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id cpp/unaliased-ssa-sanity-check - */ - -import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll index 90e9b4ef920..dcc013fd387 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll @@ -84,8 +84,6 @@ class GVN extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index d297097abd9..2ce23f098a2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -1,7 +1,7 @@ private import cpp private import semmle.code.cpp.Print private import semmle.code.cpp.ir.implementation.IRType -private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw private int getPointerSize() { result = max(any(NullPointerType t).getSize()) } @@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) { predicate hasOpaqueType(Type tag, int byteSize) { isOpaqueType(tag) and byteSize = getTypeSize(tag) or - tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize) + tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize) } /** @@ -191,7 +191,7 @@ private newtype TCppType = TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or TFunctionGLValueType() or TGLValueAddressType(Type type) or - TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or + TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or TUnknownType() /** @@ -203,6 +203,7 @@ private newtype TCppType = * of a `VariableAddress` where the variable is of reference type) */ class CppType extends TCppType { + /** Gets a textual representation of this type. */ string toString() { none() } /** Gets a string used in IR dumps */ @@ -224,6 +225,10 @@ class CppType extends TCppType { */ predicate hasType(Type type, boolean isGLValue) { none() } + /** + * Holds if this type represents the C++ type `type`. If `isGLValue` is `true`, then this type + * represents a glvalue of type `type`. Otherwise, it represents a prvalue of type `type`. + */ final predicate hasUnspecifiedType(Type type, boolean isGLValue) { exists(Type specifiedType | hasType(specifiedType, isGLValue) and @@ -357,7 +362,7 @@ CppType getTypeForPRValueOrUnknown(Type type) { /** * Gets the `CppType` that represents a glvalue of type `type`. */ -CppType getTypeForGLValue(Type type) { result.hasType(type, true) } +CppGLValueAddressType getTypeForGLValue(Type type) { result.hasType(type, true) } /** * Gets the `CppType` that represents a prvalue of type `int`. @@ -539,7 +544,10 @@ string getOpaqueTagIdentityString(Type tag) { result = getTypeIdentityString(tag) } -module LanguageTypeSanity { +module LanguageTypeConsistency { + /** + * Consistency query to detect C++ `Type` objects which have no corresponding `CppType` object. + */ query predicate missingCppType(Type type, string message) { not exists(getTypeForPRValue(type)) and exists(type.getSize()) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll index 6034ebc5674..4af31745ab2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll @@ -1,3 +1,15 @@ +/** + * Provides predicates for manipulating integer constants that are tracked by constant folding and + * similar analyses. + */ + +/** + * An alias used to represent the constant value of an integer, if one can be determined. If no + * single constant value can be determined, or if the constant value is out of the representable + * range, it will be represented as the special value `unknown()`. This allows `IntValue` to be used + * in contexts where there must always be a value for the `IntValue`, even if no constant value is + * known. + */ class IntValue = int; /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll index 2cd44a08f9e..c3328051286 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll @@ -3,7 +3,8 @@ newtype TTempVariableTag = ReturnValueTempVar() or ThrowTempVar() or LambdaTempVar() or - EllipsisTempVar() + EllipsisTempVar() or + ThisTempVar() string getTempVariableTagId(TTempVariableTag tag) { tag = ConditionValueTempVar() and result = "CondVal" @@ -15,4 +16,6 @@ string getTempVariableTagId(TTempVariableTag tag) { tag = LambdaTempVar() and result = "Lambda" or tag = EllipsisTempVar() and result = "Ellipsis" + or + tag = ThisTempVar() and result = "This" } diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index f02d05be711..bc105d64066 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -4,6 +4,7 @@ private import implementations.Fread private import implementations.Gets private import implementations.IdentityFunction private import implementations.Inet +private import implementations.MemberFunction private import implementations.Memcpy private import implementations.Memset private import implementations.Printf @@ -14,3 +15,4 @@ private import implementations.Strdup private import implementations.Strftime private import implementations.StdString private import implementations.Swap +private import implementations.GetDelim diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 782800d0fa2..1f82b90bff4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of allocation + * Provides implementation classes modeling various methods of allocation * (`malloc`, `new` etc). See `semmle.code.cpp.models.interfaces.Allocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index 2ef355bf398..4f0341b673e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of deallocation + * Provides implementation classes modeling various methods of deallocation * (`free`, `delete` etc). See `semmle.code.cpp.models.interfaces.Deallocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll new file mode 100644 index 00000000000..3f376cf2ff0 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll @@ -0,0 +1,40 @@ +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.SideEffect +import semmle.code.cpp.models.interfaces.FlowSource + +/** + * The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`. + */ +class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, RemoteFlowFunction { + GetDelimFunction() { hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } + + override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) { + i.isParameter(3) and o.isParameterDeref(0) + } + + override predicate parameterNeverEscapes(int index) { index = [0, 1, 3] } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + i = [0, 1] and + buffer = false and + mustWrite = false + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 3 and buffer = false + } + + override predicate hasRemoteFlowSource(FunctionOutput output, string description) { + output.isParameterDeref(0) and + description = "String read by " + this.getName() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index e5e45729e0d..d3c8d2a7f6f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `gets` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.ArrayFunction @@ -48,4 +53,17 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias output.isParameterDeref(0) and description = "String read by " + this.getName() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + not hasGlobalOrStdName("gets") and + bufParam = 0 and + countParam = 1 + } + + override predicate hasArrayWithUnknownSize(int bufParam) { + hasGlobalOrStdName("gets") and + bufParam = 0 + } + + override predicate hasArrayOutput(int bufParam) { bufParam = 0 } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll new file mode 100644 index 00000000000..f7cd9261310 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll @@ -0,0 +1,72 @@ +/** + * Provides models for C++ constructors and user-defined operators. + */ + +import cpp +import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Taint + +/** + * Model for C++ conversion constructors. + */ +class ConversionConstructorModel extends ConversionConstructor, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. + } +} + +/** + * Model for C++ copy constructors. + */ +class CopyConstructorModel extends CopyConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. + } +} + +/** + * Model for C++ move constructors. + */ +class MoveConstructorModel extends MoveConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. + } +} + +/** + * Model for C++ copy assignment operators. + */ +class CopyAssignmentOperatorModel extends CopyAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model copy assignment as data flow + } +} + +/** + * Model for C++ move assignment operators. + */ +class MoveAssignmentOperatorModel extends MoveAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model move assignment as data flow + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 0951daea11b..ef4aa8b7290 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `memcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 7fc7fbfc9e5..2c34369aee4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `memset` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 403e8fae1de..61dd3bc50b9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -1,3 +1,10 @@ +/** + * Provides implementation classes modeling various standard formatting + * functions (`printf`, `snprintf` etc). + * See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage + * information. + */ + import semmle.code.cpp.models.interfaces.FormattingFunction import semmle.code.cpp.models.interfaces.Alias @@ -19,7 +26,7 @@ class Printf extends FormattingFunction, AliasFunction { override int getFormatParameterIndex() { result = 0 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("wprintf") or hasGlobalName("wprintf_s") } @@ -47,7 +54,7 @@ class Fprintf extends FormattingFunction { override int getFormatParameterIndex() { result = 1 } - override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } + deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } override int getOutputParameterIndex() { result = 0 } } @@ -59,18 +66,31 @@ class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName("sprintf") or - hasGlobalName("_sprintf_l") or - hasGlobalName("__swprintf_l") or - hasGlobalOrStdName("wsprintf") or - hasGlobalName("g_strdup_printf") or - hasGlobalName("g_sprintf") or + // sprintf(dst, format, args...) + hasGlobalOrStdName("sprintf") + or + // _sprintf_l(dst, format, locale, args...) + hasGlobalName("_sprintf_l") + or + // __swprintf_l(dst, format, locale, args...) + hasGlobalName("__swprintf_l") + or + // wsprintf(dst, format, args...) + hasGlobalOrStdName("wsprintf") + or + // g_strdup_printf(format, ...) + hasGlobalName("g_strdup_printf") + or + // g_sprintf(dst, format, ...) + hasGlobalName("g_sprintf") + or + // __builtin___sprintf_chk(dst, flag, os, format, ...) hasGlobalName("__builtin___sprintf_chk") ) and not exists(getDefinition().getFile().getRelativePath()) } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -136,7 +156,7 @@ class Snprintf extends FormattingFunction { else result = getFirstFormatArgumentIndex() - 1 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -201,7 +221,7 @@ class StringCchPrintf extends FormattingFunction { if getName().matches("%Ex") then result = 5 else result = 2 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index c831a8bf357..8e1739fe6a7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -20,9 +20,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE name = "strpbrk" or name = "strcmp" or name = "strcspn" or - name = "strlen" or name = "strncmp" or - name = "strnlen" or name = "strrchr" or name = "strspn" or name = "strtod" or @@ -30,16 +28,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE name = "strtol" or name = "strtoll" or name = "strtoq" or - name = "strtoul" or - name = "wcslen" - ) - or - hasGlobalName(name) and - ( - name = "_mbslen" or - name = "_mbslen_l" or - name = "_mbstrlen" or - name = "_mbstrlen_l" + name = "strtoul" ) ) } @@ -90,6 +79,52 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE } } +class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { + StrLenFunction() { + exists(string name | + hasGlobalOrStdName(name) and + ( + name = "strlen" or + name = "strnlen" or + name = "wcslen" + ) + or + hasGlobalName(name) and + ( + name = "_mbslen" or + name = "_mbslen_l" or + name = "_mbstrlen" or + name = "_mbstrlen_l" + ) + ) + } + + override predicate hasArrayInput(int bufParam) { + getParameter(bufParam).getUnspecifiedType() instanceof PointerType + } + + override predicate hasArrayWithNullTerminator(int bufParam) { + getParameter(bufParam).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterNeverEscapes(int i) { + getParameter(i).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterEscapesOnlyViaReturn(int i) { none() } + + override predicate parameterIsAlwaysReturned(int i) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + getParameter(i).getUnspecifiedType() instanceof PointerType and + buffer = true + } +} + class PureFunction extends TaintFunction, SideEffectFunction { PureFunction() { exists(string name | diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 9c6ebd1a877..9ffef420a19 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -1,19 +1,5 @@ import semmle.code.cpp.models.interfaces.Taint -/** - * The `std::basic_string` constructor(s). - */ -class StdStringConstructor extends TaintFunction { - pragma[noinline] - StdStringConstructor() { this.hasQualifiedName("std", "basic_string", "basic_string") } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // flow from any constructor argument to return value - input.isParameter(_) and - output.isReturnValue() - } -} - /** * The standard function `std::string.c_str`. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index d44b28f041d..9acd5b32d4f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strcat` and various similar functions. + * See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint @@ -19,6 +24,21 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid ) } + /** + * Gets the index of the parameter that is the size of the copy (in characters). + */ + int getParamSize() { exists(getParameter(2)) and result = 2 } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = 1 } + + /** + * Gets the index of the parameter that is the destination to be appended to. + */ + int getParamDest() { result = 0 } + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameter(0) and output.isReturnValue() diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index c7f0898f358..9a15b823041 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint @@ -8,70 +13,110 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") or - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") + exists(string name | name = getName() | + // strcpy(dst, src) + name = "strcpy" + or + // wcscpy(dst, src) + name = "wcscpy" + or + // _mbscpy(dst, src) + name = "_mbscpy" + or + ( + name = "strcpy_s" or // strcpy_s(dst, max_amount, src) + name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) + name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) + ) and + // exclude the 2-parameter template versions + // that find the size of a fixed size destination buffer. + getNumberOfParameters() = 3 + or + // strncpy(dst, src, max_amount) + name = "strncpy" + or + // _strncpy_l(dst, src, max_amount, locale) + name = "_strncpy_l" + or + // wcsncpy(dst, src, max_amount) + name = "wcsncpy" + or + // _wcsncpy_l(dst, src, max_amount, locale) + name = "_wcsncpy_l" + or + // _mbsncpy(dst, src, max_amount) + name = "_mbsncpy" + or + // _mbsncpy_l(dst, src, max_amount, locale) + name = "_mbsncpy_l" + ) } - override predicate hasArrayInput(int bufParam) { bufParam = 1 } + /** + * Holds if this is one of the `strcpy_s` variants. + */ + private predicate isSVariant() { + exists(string name | name = getName() | name.suffix(name.length() - 2) = "_s") + } - override predicate hasArrayOutput(int bufParam) { bufParam = 0 } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { + if isSVariant() + then result = 1 + else + if exists(getName().indexOf("ncpy")) + then result = 2 + else none() + } - override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 1 } + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { if isSVariant() then result = 2 else result = 1 } + + /** + * Gets the index of the parameter that is the destination of the copy. + */ + int getParamDest() { result = 0 } + + override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() } + + override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = getParamSrc() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - ( - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - bufParam = 0 and - countParam = 2 + bufParam = getParamDest() and + countParam = getParamSize() } override predicate hasArrayWithUnknownSize(int bufParam) { - ( - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") - ) and - bufParam = 0 + not exists(getParamSize()) and + bufParam = getParamDest() } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - input.isParameterDeref(1) and - output.isParameterDeref(0) + not exists(getParamSize()) and + input.isParameterDeref(getParamSrc()) and + output.isParameterDeref(getParamDest()) or - input.isParameterDeref(1) and + not exists(getParamSize()) and + input.isParameterDeref(getParamSrc()) and output.isReturnValueDeref() or - input.isParameter(0) and + input.isParameter(getParamDest()) and output.isReturnValue() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // these may do only a partial copy of the input buffer to the output + // buffer + exists(getParamSize()) and + input.isParameter(getParamSrc()) and ( - // these may do only a partial copy of the input buffer to the output - // buffer - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - input.isParameter(2) and - ( - output.isParameterDeref(0) or + output.isParameterDeref(getParamDest()) or output.isReturnValueDeref() ) } @@ -81,17 +126,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i = 0 and + i = getParamDest() and buffer = true and mustWrite = false } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - i = 1 and + i = getParamSrc() and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { - hasArrayWithVariableSize(i, result) + i = getParamDest() and + result = getParamSize() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll index f7d122db259..3497ab9a065 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strdup` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll index b4c7f69bde4..3e58fd8c258 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll @@ -10,10 +10,7 @@ class Strftime extends TaintFunction, ArrayFunction { input.isParameterDeref(2) or input.isParameterDeref(3) ) and - ( - output.isParameterDeref(0) or - output.isReturnValue() - ) + output.isParameterDeref(0) } override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 2 } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll index 81a40cd349a..1ebf40b1f01 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * allocate memory, such as the standard `malloc` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll index 872cfcd2997..c1b65d62706 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll @@ -19,5 +19,10 @@ import semmle.code.cpp.models.Models * to destinations; that is covered by `TaintModel.qll`. */ abstract class DataFlowFunction extends Function { + /** + * Holds if data can be copied from the argument, qualifier, or buffer + * represented by `input` to the return value or buffer represented by + * `output` + */ abstract predicate hasDataFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll index 9223592ef67..23eca516418 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * deallocate memory, such as the standard `free` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 7227e6e9513..f97646ca833 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -1,6 +1,6 @@ /** * Provides a class for modeling `printf`-style formatting functions. To use - * this QL library, create a QL class extending `DataFlowFunction` with a + * this QL library, create a QL class extending `FormattingFunction` with a * characteristic predicate that selects the function or set of functions you * are modeling. Within that class, override the predicates provided by * `FormattingFunction` to match the flow within that function. @@ -44,7 +44,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction { /** Gets the position at which the format parameter occurs. */ abstract int getFormatParameterIndex(); - override string getCanonicalQLClass() { result = "FormattingFunction" } + override string getAPrimaryQlClass() { result = "FormattingFunction" } /** * Holds if this `FormattingFunction` is in a context that supports diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index d0fbb50ebfa..ef7174a14c7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -108,6 +108,20 @@ class FunctionInput extends TFunctionInput { predicate isQualifierAddress() { none() } } +/** + * The input value of a parameter. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameter` representing the value of `n` (with type `int`) on entry to the + * function. + * - There is an `InParameter` representing the value of `p` (with type `char*`) on entry to the + * function. + * - There is an `InParameter` representing the "value" of the reference `r` (with type `float&`) on + * entry to the function, _not_ the value of the referred-to `float`. + */ class InParameter extends FunctionInput, TInParameter { ParameterIndex index; @@ -121,6 +135,21 @@ class InParameter extends FunctionInput, TInParameter { override predicate isParameter(ParameterIndex i) { i = index } } +/** + * The input value pointed to by a pointer parameter to a function, or the input value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameterDeref` with `getIndex() = 1` that represents the value of `*p` (with + * type `char`) on entry to the function. + * - There is an `InParameterDeref` with `getIndex() = 2` that represents the value of `r` (with + * type `float`) on entry to the function. + * - There is no `InParameterDeref` representing the value of `n`, because `n` is neither a pointer + * nor a reference. + */ class InParameterDeref extends FunctionInput, TInParameterDeref { ParameterIndex index; @@ -134,12 +163,36 @@ class InParameterDeref extends FunctionInput, TInParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The input value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierObject` represents the value of `*this` (with type `C const`) on entry to the + * function. + */ class InQualifierObject extends FunctionInput, TInQualifierObject { override string toString() { result = "InQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The input value of the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierAddress` represents the value of `this` (with type `C const *`) on entry to the + * function. + */ class InQualifierAddress extends FunctionInput, TInQualifierAddress { override string toString() { result = "InQualifierAddress" } @@ -265,6 +318,21 @@ class FunctionOutput extends TFunctionOutput { deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } } +/** + * The output value pointed to by a pointer parameter to a function, or the output value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `OutParameterDeref` with `getIndex()=1` that represents the value of `*p` (with + * type `char`) on return from the function. + * - There is an `OutParameterDeref` with `getIndex()=2` that represents the value of `r` (with + * type `float`) on return from the function. + * - There is no `OutParameterDeref` representing the value of `n`, because `n` is neither a + * pointer nor a reference. + */ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { ParameterIndex index; @@ -277,18 +345,62 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The output value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r); + * }; + * ``` + * - The `OutQualifierObject` represents the value of `*this` (with type `C`) on return from the + * function. + */ class OutQualifierObject extends FunctionOutput, TOutQualifierObject { override string toString() { result = "OutQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The value returned by a function. + * + * Example: + * ``` + * int getInt(); + * char* getPointer(); + * float& getReference(); + * ``` + * - `OutReturnValue` represents the value returned by + * `getInt()` (with type `int`). + * - `OutReturnValue` represents the value returned by + * `getPointer()` (with type `char*`). + * - `OutReturnValue` represents the "value" of the reference returned by `getReference()` (with + * type `float&`), _not_ the value of the referred-to `float`. + */ class OutReturnValue extends FunctionOutput, TOutReturnValue { override string toString() { result = "OutReturnValue" } override predicate isReturnValue() { any() } } +/** + * The output value pointed to by the return value of a function, if the function returns a pointer, + * or the output value referred to by the return value of a function, if the function returns a + * reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `OutReturnValueDeref` represents the value of `*getPointer()` (with type `char`). + * - `OutReturnValueDeref` represents the value of `getReference()` (with type `float`). + * - `OutReturnValueDeref` does not represent the return value of `getInt()` because the return type + * of `getInt()` is neither a pointer nor a reference. + */ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref { override string toString() { result = "OutReturnValueDeref" } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index 02e7c8e78a1..fe617533f59 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -15,11 +15,18 @@ import semmle.code.cpp.models.Models * A library function for which a taint-tracking library should propagate taint * from a parameter or qualifier to an output buffer, return value, or qualifier. * + * An expression is tainted if it could be influenced by an attacker to have + * an unusual value. + * * Note that this does not include direct copying of values; that is covered by * DataFlowModel.qll. If a value is sometimes copied in full, and sometimes * altered (for example copying a string with `strncpy`), this is also considered * data flow. */ abstract class TaintFunction extends Function { + /** + * Holds if data passed into the argument, qualifier, or buffer represented by + * `input` influences the return value or buffer represented by `output` + */ abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql b/cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql similarity index 75% rename from cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql rename to cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql index cbd5410ffde..ac4102e6750 100644 --- a/cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql +++ b/cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql @@ -1,14 +1,14 @@ /** - * @name Padding Sanity Check - * @description Performs sanity checks for the padding library. This query should have no results. + * @name Padding Consistency Check + * @description Performs consistency checks for the padding library. This query should have no results. * @kind table - * @id cpp/padding-sanity-check + * @id cpp/padding-consistency-check */ import Padding /* - * Sanity-check: Find discrepancies between computed and actual size on LP64. + * Consistency-check: Find discrepancies between computed and actual size on LP64. */ /* diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll index ea12434ac5b..e402b672cbc 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for recognizing floating point expressions which cannot be NaN. + */ + import cpp private import semmle.code.cpp.rangeanalysis.RangeSSA diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll index 3c9177ad9db..47289c7552b 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll @@ -11,8 +11,17 @@ private float lowerBoundFC(Expr expr) { result = lowerBound(expr.getFullyConvert /** Gets the upper bound of the fully converted expression. */ private float upperBoundFC(Expr expr) { result = upperBound(expr.getFullyConverted()) } +/** + * Describes which side of a pointless comparison is known to be smaller. + */ newtype SmallSide = + /** + * Represents that the left side of a pointless comparison is known to be smaller. + */ LeftIsSmaller() or + /** + * Represents that the right side of a pointless comparison is known to be smaller. + */ RightIsSmaller() /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll index 9e99fcb8204..b3f0ac1d57c 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll @@ -5,7 +5,13 @@ import cpp * relation) or 'non-strict' (a `<=` or `>=` relation). */ newtype RelationStrictness = + /** + * Represents that a relation is 'strict' (that is, a `<` or `>` relation). + */ Strict() or + /** + * Represents that a relation is 'non-strict' (that is, a `<=` or `>=` relation) + */ Nonstrict() /** @@ -13,7 +19,13 @@ newtype RelationStrictness = * relation) or 'lesser' (a `<` or `<=` relation). */ newtype RelationDirection = + /** + * Represents that a relation is 'greater' (that is, a `>` or `>=` relation). + */ Greater() or + /** + * Represents that a relation is 'lesser' (that is, a `<` or `<=` relation). + */ Lesser() private RelationStrictness negateStrictness(RelationStrictness strict) { @@ -28,12 +40,18 @@ private RelationDirection negateDirection(RelationDirection dir) { dir = Lesser() and result = Greater() } +/** + * Holds if `dir` is `Greater` (that is, a `>` or `>=` relation) + */ boolean directionIsGreater(RelationDirection dir) { dir = Greater() and result = true or dir = Lesser() and result = false } +/** + * Holds if `dir` is `Lesser` (that is, a `<` or `<=` relation) + */ boolean directionIsLesser(RelationDirection dir) { dir = Greater() and result = false or diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll index 99e6539658d..95079bb871e 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -25,6 +25,10 @@ import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSAUtils private import RangeAnalysisUtils +/** + * The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA. + * This class provides the range-analysis SSA logic. + */ library class RangeSSA extends SSAHelper { RangeSSA() { this = 1 } @@ -84,6 +88,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { /** Gets the control flow node for this definition. */ ControlFlowNode getDefinition() { result = this } + /** Gets the basic block containing this definition. */ BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Whether this definition is a phi node for variable `v`. */ @@ -97,11 +102,13 @@ class RangeSsaDefinition extends ControlFlowNodeBase { guard_defn(v, guard, this, branch) } + /** Gets the primary location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } /** Whether this definition is from a parameter */ predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() } + /** Gets a definition of `v` that is a phi input for this basic block. */ RangeSsaDefinition getAPhiInput(StackVariable v) { this.isPhiNode(v) and exists(BasicBlock pred | @@ -153,6 +160,9 @@ class RangeSsaDefinition extends ControlFlowNodeBase { ) } + /** + * Holds if this definition of the variable `v` reached the end of the basic block `b`. + */ predicate reachesEndOfBB(StackVariable v, BasicBlock b) { exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b)) } diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 7751b47cb6c..9ebd2b2219a 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -140,6 +140,22 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { } } +/** + * Gets the floor of `v`, with additional logic to work around issues with + * large numbers. + */ +bindingset[v] +float safeFloor(float v) { + // return the floor of v + v.abs() < 2.pow(31) and + result = v.floor() + or + // `floor()` doesn't work correctly on large numbers (since it returns an integer), + // so fall back to unrounded numbers at this scale. + not v.abs() < 2.pow(31) and + result = v +} + /** 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 @@ -708,8 +724,8 @@ private float getLowerBoundsImpl(Expr expr) { exists(RShiftExpr rsExpr, float left, int right | rsExpr = expr and left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and - result = left / 2.pow(right) + right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and + result = safeFloor(left / 2.pow(right)) ) } @@ -877,8 +893,8 @@ private float getUpperBoundsImpl(Expr expr) { exists(RShiftExpr rsExpr, float left, int right | rsExpr = expr and left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and - result = left / 2.pow(right) + right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and + result = safeFloor(left / 2.pow(right)) ) } diff --git a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll index 4c53f34c936..7525b1f0d68 100644 --- a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll @@ -10,6 +10,7 @@ import semmle.code.cpp.commons.Alloc import semmle.code.cpp.commons.Buffer import semmle.code.cpp.commons.Scanf import semmle.code.cpp.models.implementations.Strcat +import semmle.code.cpp.models.implementations.Strcpy /* * --- BufferWrite framework --- @@ -106,68 +107,19 @@ abstract class BufferWriteCall extends BufferWrite, FunctionCall { } * A call to a variant of `strcpy`. */ class StrCopyBW extends BufferWriteCall { - StrCopyBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | - // strcpy(dst, src) - name = "strcpy" - or - // wcscpy(dst, src) - name = "wcscpy" - or - // _mbscpy(dst, src) - name = "_mbscpy" - or - ( - name = "strcpy_s" or // strcpy_s(dst, max_amount, src) - name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) - name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) - ) and - // exclude the 2-parameter template versions - // that find the size of a fixed size destination buffer. - fn.getNumberOfParameters() = 3 - or - // strncpy(dst, src, max_amount) - name = "strncpy" - or - // strncpy_l(dst, src, max_amount, locale) - name = "strncpy_l" - or - // wcsncpy(dst, src, max_amount) - name = "wcsncpy" - or - // _wcsncpy_l(dst, src, max_amount, locale) - name = "_wcsncpy_l" - or - // _mbsncpy(dst, src, max_amount) - name = "_mbsncpy" - or - // _mbsncpy_l(dst, src, max_amount, locale) - name = "_mbsncpy_l" - ) - } + StrcpyFunction f; - int getParamSize() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - ( - if name.suffix(name.length() - 2) = "_s" - then result = 1 - else - if exists(name.indexOf("ncpy")) - then result = 2 - else none() - ) - ) - } + StrCopyBW() { getTarget() = f.(TopLevelFunction) } - int getParamSrc() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - (if name.suffix(name.length() - 2) = "_s" then result = 2 else result = 1) - ) - } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { result = f.getParamSize() } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -175,7 +127,7 @@ class StrCopyBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } @@ -192,11 +144,19 @@ class StrCopyBW extends BufferWriteCall { * A call to a variant of `strcat`. */ class StrCatBW extends BufferWriteCall { - StrCatBW() { exists(TopLevelFunction fn | fn = getTarget() and fn instanceof StrcatFunction) } + StrcatFunction f; - int getParamSize() { if exists(getArgument(2)) then result = 2 else none() } + StrCatBW() { getTarget() = f.(TopLevelFunction) } - int getParamSrc() { result = 1 } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { result = f.getParamSize() } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -204,7 +164,7 @@ class StrCatBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } @@ -221,8 +181,10 @@ class StrCatBW extends BufferWriteCall { * A call to a variant of `sprintf`. */ class SprintfBW extends BufferWriteCall { + FormattingFunction f; + SprintfBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | + exists(string name | f = getTarget().(TopLevelFunction) and name = f.getName() | /* * C sprintf variants: */ @@ -258,10 +220,7 @@ class SprintfBW extends BufferWriteCall { } override Type getBufferType() { - exists(FormattingFunction f | - f = this.getTarget() and - result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() - ) + result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() } override Expr getASource() { @@ -270,7 +229,7 @@ class SprintfBW extends BufferWriteCall { result = this.(FormattingFunctionCall).getFormatArgument(_) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getOutputParameterIndex()) } override int getMaxData() { exists(FormatLiteral fl | @@ -349,6 +308,9 @@ class SnprintfBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the size of the destination (in characters). + */ int getParamSize() { result = 1 } override Type getBufferType() { @@ -399,6 +361,9 @@ class GetsBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the maximum number of characters to be read. + */ int getParamSize() { if exists(getArgument(1)) then result = 1 else none() } override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() } @@ -434,6 +399,9 @@ class ScanfBW extends BufferWrite { ) } + /** + * Gets the index of the parameter that is the first format argument. + */ int getParamArgs() { exists(FunctionCall fc | this = fc.getArgument(_) and diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index 48fb60442c1..5a24184e1a2 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -2,21 +2,44 @@ import cpp import semmle.code.cpp.security.FunctionWithWrappers +import semmle.code.cpp.models.interfaces.SideEffect /** * A function for running a command using a command interpreter. */ -class SystemFunction extends FunctionWithWrappers { +class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction { SystemFunction() { - hasGlobalOrStdName("system") or - hasGlobalName("popen") or + hasGlobalOrStdName("system") or // system(command) + hasGlobalName("popen") or // popen(command, mode) // Windows variants - hasGlobalName("_popen") or - hasGlobalName("_wpopen") or - hasGlobalName("_wsystem") + hasGlobalName("_popen") or // _popen(command, mode) + hasGlobalName("_wpopen") or // _wpopen(command, mode) + hasGlobalName("_wsystem") // _wsystem(command) } override predicate interestingArg(int arg) { arg = 0 } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { + hasGlobalOrStdName("system") or + hasGlobalName("_wsystem") + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + (i = 0 or i = 1) and + buffer = true + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 61d64673314..d8b2d44c923 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -1,8 +1,13 @@ -// Common predicates relating to encryption in C and C++ +/** + * Provides predicates relating to encryption in C and C++. + */ + import cpp -/** A blacklist of algorithms that are known to be insecure */ -string algorithmBlacklist() { +/** + * Gets the name of an algorithm that is known to be insecure. + */ +string getAnInsecureAlgorithmName() { result = "DES" or result = "RC2" or result = "RC4" or @@ -10,29 +15,36 @@ string algorithmBlacklist() { result = "ARCFOUR" // a variant of RC4 } -// these are only bad if they're being used for encryption, and it's -// hard to know when that's happening -string hashAlgorithmBlacklist() { +/** + * Gets the name of a hash algorithm that is insecure if it is being used for + * encryption (but it is hard to know when that is happening). + */ +string getAnInsecureHashAlgorithmName() { result = "SHA1" or result = "MD5" } -/** A regex for matching strings that look like they contain a blacklisted algorithm */ -string algorithmBlacklistRegex() { +/** + * Gets the regular expression used for matching strings that look like they + * contain an algorithm that is known to be insecure. + */ +string getInsecureAlgorithmRegex() { result = // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases - "(^|.*[^A-Z])(" + strictconcat(algorithmBlacklist(), "|") + ")([^A-Z].*|$)" + "|" + + "(^|.*[^A-Z])(" + strictconcat(getAnInsecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + // for lowercase, we want to be careful to avoid being confused by camelCase // hence we require two preceding uppercase letters to be sure of a case switch, // or a preceding non-alphabetic character - "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(algorithmBlacklist().toLowerCase(), "|") + + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getAnInsecureAlgorithmName().toLowerCase(), "|") + ")([^a-z].*|$)" } -/** A whitelist of algorithms that are known to be secure */ -string algorithmWhitelist() { +/** + * Gets the name of an algorithm that is known to be secure. + */ +string getASecureAlgorithmName() { result = "RSA" or result = "SHA256" or result = "CCM" or @@ -42,17 +54,47 @@ string algorithmWhitelist() { result = "ECIES" } -/** A regex for matching strings that look like they contain a whitelisted algorithm */ -string algorithmWhitelistRegex() { - // The implementation of this is a duplicate of algorithmBlacklistRegex, as it isn't - // possible to have string -> string functions at the moment - // algorithms usually appear in names surrounded by characters that are not - // alphabetical characters in the same case. This handles the upper and lower - // case cases - result = "(^|.*[^A-Z])" + algorithmWhitelist() + "([^A-Z].*|$)" - or - // for lowercase, we want to be careful to avoid being confused by camelCase - // hence we require two preceding uppercase letters to be sure of a case switch, - // or a preceding non-alphabetic character - result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + algorithmWhitelist().toLowerCase() + "([^a-z].*|$)" +/** + * Gets a regular expression for matching strings that look like they + * contain an algorithm that is known to be secure. + */ +string getSecureAlgorithmRegex() { + result = + // algorithms usually appear in names surrounded by characters that are not + // alphabetical characters in the same case. This handles the upper and lower + // case cases + "(^|.*[^A-Z])(" + strictconcat(getASecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + + // for lowercase, we want to be careful to avoid being confused by camelCase + // hence we require two preceding uppercase letters to be sure of a case + // switch, or a preceding non-alphabetic character + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getASecureAlgorithmName().toLowerCase(), "|") + + ")([^a-z].*|$)" } + +/** + * DEPRECATED: Terminology has been updated. Use `getAnInsecureAlgorithmName()` + * instead. + */ +deprecated string algorithmBlacklist() { result = getAnInsecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use + * `getAnInsecureHashAlgorithmName()` instead. + */ +deprecated string hashAlgorithmBlacklist() { result = getAnInsecureHashAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getInsecureAlgorithmRegex()` instead. + */ +deprecated string algorithmBlacklistRegex() { result = getInsecureAlgorithmRegex() } + +/** + * DEPRECATED: Terminology has been updated. Use `getASecureAlgorithmName()` + * instead. + */ +deprecated string algorithmWhitelist() { result = getASecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getSecureAlgorithmRegex()` instead. + */ +deprecated string algorithmWhitelistRegex() { result = getSecureAlgorithmRegex() } diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 219f3d0a75b..f4c52801118 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -1,13 +1,23 @@ +/** + * Provides classes for modeling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. + */ + import cpp /** - * A function call that writes to a file + * A function call that writes to a file. */ class FileWrite extends Expr { FileWrite() { fileWrite(this, _, _) } + /** + * Gets a source expression of this write. + */ Expr getASource() { fileWrite(this, result, _) } + /** + * Gets the expression for the object being written to. + */ Expr getDest() { fileWrite(this, _, result) } } @@ -44,17 +54,17 @@ class BasicOStreamCall extends FunctionCall { */ abstract class ChainedOutputCall extends BasicOStreamCall { /** - * The source expression of this output. + * Gets the source expression of this output. */ abstract Expr getSource(); /** - * The immediate destination expression of this output. + * Gets the immediate destination expression of this output. */ abstract Expr getDest(); /** - * The destination at the far left-hand end of the output chain. + * Gets the destination at the far left-hand end of the output chain. */ Expr getEndDest() { // recurse into the destination @@ -108,7 +118,7 @@ class WriteFunctionCall extends ChainedOutputCall { } /** - * Whether the function call is a call to << that eventually starts at the given file stream. + * Whether the function call is a call to `operator<<` or a similar function, that eventually starts at the given file stream. */ private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest) { source = out.getSource() and diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 23dda0ddb1e..5451011b351 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -1,3 +1,20 @@ +/** + * Provides predicates for identifying functions that wrap other functions, + * passing the same arguments from the outer call into the inner call. In the + * following example `MyMalloc` wraps a call to `malloc`, passing in the `size` + * parameter: + * ``` + * void *MyMalloc(size_t size) + * { + * void *ptr = malloc(size); + * + * // ... additional logic? + * + * return ptr; + * } + * ``` + */ + import cpp import PrintfLike private import TaintTracking @@ -152,6 +169,9 @@ abstract class FunctionWithWrappers extends Function { } } +/** + * A `printf`-like formatting function. + */ class PrintfLikeFunction extends FunctionWithWrappers { PrintfLikeFunction() { printfLikeFunction(this, _) } diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index 06abfdb454d..cac3891d5ff 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -1,12 +1,19 @@ +/** + * Provides classes for modeling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. + */ + import cpp import FileWrite /** - * A function call that writes to standard output or standard error + * A function call that writes to standard output or standard error. */ class OutputWrite extends Expr { OutputWrite() { outputWrite(this, _) } + /** + * Gets a source expression for this output. + */ Expr getASource() { outputWrite(this, result) } } @@ -49,7 +56,7 @@ private predicate outputFile(Expr e) { } /** - * is the function call a write to standard output or standard error from 'source' + * Holds if the function call is a write to standard output or standard error from 'source'. */ private predicate outputWrite(Expr write, Expr source) { exists(Function f, int arg | diff --git a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll index 59993954cc8..e7ad1c559e6 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll @@ -1,11 +1,14 @@ +/** + * Provides predicates for reasoning about when the value of an expression is + * guarded by an operation such as `<`, which confines its range. + */ + import cpp import semmle.code.cpp.controlflow.Dominance -/* - * Guarding +/** + * Holds if the value of `use` is guarded using `abs`. */ - -/** is the size of this use guarded using 'abs'? */ predicate guardedAbs(Operation e, Expr use) { exists(FunctionCall fc | fc.getTarget().getName() = "abs" | fc.getArgument(0).getAChild*() = use and @@ -13,7 +16,10 @@ predicate guardedAbs(Operation e, Expr use) { ) } -/** This is `BasicBlock.getNode`, restricted to `Stmt` for performance. */ +/** + * Gets the position of `stmt` in basic block `block` (this is a thin layer + * over `BasicBlock.getNode`, intended to improve performance). + */ pragma[noinline] private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt } @@ -30,7 +36,9 @@ private predicate stmtDominates(Stmt dominator, Stmt dominated) { bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock()) } -/** is the size of this use guarded to be less than something? */ +/** + * Holds if the value of `use` is guarded to be less than something. + */ pragma[nomagic] predicate guardedLesser(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -54,7 +62,9 @@ predicate guardedLesser(Operation e, Expr use) { guardedAbs(e, use) } -/** is the size of this use guarded to be greater than something? */ +/** + * Holds if the value of `use` is guarded to be greater than something. + */ pragma[nomagic] predicate guardedGreater(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -78,10 +88,14 @@ predicate guardedGreater(Operation e, Expr use) { guardedAbs(e, use) } -/** a use of a given variable */ +/** + * Gets a use of a given variable `v`. + */ VariableAccess varUse(LocalScopeVariable v) { result = v.getAnAccess() } -/** is e not guarded against overflow by use? */ +/** + * Holds if `e` is not guarded against overflow by `use`. + */ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | @@ -100,7 +114,9 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { ) } -/** is e not guarded against underflow by use? */ +/** + * Holds if `e` is not guarded against underflow by `use`. + */ predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | diff --git a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll index 47d0ca3aa93..197a332aa1a 100644 --- a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll +++ b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll @@ -1,6 +1,18 @@ +/** + * Provides a predicate for identifying formatting functions like `printf`. + * + * Consider using the newer model in + * `semmle.code.cpp.models.interfaces.FormattingFunction` directly instead of + * this library. + */ + import semmle.code.cpp.commons.Printf import external.ExternalArtifact +/** + * Holds if `func` is a `printf`-like formatting function and `formatArg` is + * the index of the format string argument. + */ predicate printfLikeFunction(Function func, int formatArg) { formatArg = func.(FormattingFunction).getFormatParameterIndex() and not func instanceof UserDefinedFormattingFunction diff --git a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll index 8d35d80e613..64babe419c3 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll @@ -1,4 +1,4 @@ -/* +/** * Security pack options. * * see https://semmle.com/wiki/display/SD/_Configuring+SecurityOptions+for+your+code+base @@ -9,6 +9,10 @@ import semmle.code.cpp.security.Security +/** + * This class overrides `SecurityOptions` and can be used to add project + * specific customization. + */ class CustomSecurityOptions extends SecurityOptions { override predicate sqlArgument(string function, int arg) { SecurityOptions.super.sqlArgument(function, arg) diff --git a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll index 25d68fde716..553cc98351c 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll @@ -1,5 +1,14 @@ +/** + * Provides classes for heuristically identifying variables and functions that + * might contain or return a password or other sensitive information. + */ + import cpp +/** + * Holds if the name `s` suggests something might contain or return a password + * or other sensitive information. + */ bindingset[s] private predicate suspicious(string s) { ( @@ -16,14 +25,23 @@ private predicate suspicious(string s) { ) } +/** + * A variable that might contain a password or other sensitive information. + */ class SensitiveVariable extends Variable { SensitiveVariable() { suspicious(getName().toLowerCase()) } } +/** + * A function that might return a password or other sensitive information. + */ class SensitiveFunction extends Function { SensitiveFunction() { suspicious(getName().toLowerCase()) } } +/** + * An expression whose value might be a password or other sensitive information. + */ class SensitiveExpr extends Expr { SensitiveExpr() { this.(VariableAccess).getTarget() instanceof SensitiveVariable or diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll index e20dfd83efd..65836d285ad 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll @@ -1,5 +1,7 @@ /* * Support for tracking tainted data through the program. + * + * Prefer to use `semmle.code.cpp.dataflow.TaintTracking` when designing new queries. */ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll index a24820b277f..06cf4c456ce 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll @@ -1,4 +1,8 @@ /** + * DEPRECATED: we now use `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`, + * which is based on the IR but designed to behave similarly to this old + * libarary. + * * Provides the implementation of `semmle.code.cpp.security.TaintTracking`. Do * not import this file directly. */ diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll index 4f69f52caf4..48caa48a803 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll @@ -1,3 +1,7 @@ +/** + * Provides a class to model C/C++ block statements, enclosed by `{` and `}`. + */ + import semmle.code.cpp.Element import semmle.code.cpp.stmts.Stmt @@ -14,7 +18,7 @@ import semmle.code.cpp.stmts.Stmt * ``` */ class Block extends Stmt, @stmt_block { - override string getCanonicalQLClass() { result = "Block" } + override string getAPrimaryQlClass() { result = "Block" } /** * Gets a child declaration of this block. diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 1640bee0f35..6043948fce5 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1,3 +1,7 @@ +/** + * Provides a hierarchy of classes for modeling C/C++ statements. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -133,12 +137,14 @@ class Stmt extends StmtParent, @stmt { predicate isCompilerGenerated() { compgenerated(underlyingElement(this)) } } +private class TStmtParent = @stmt or @expr; + /** * An element that is the parent of a statement in the C/C++ AST. * * This is normally a statement, but may be a `StmtExpr`. */ -abstract class StmtParent extends ControlFlowNode { } +class StmtParent extends ControlFlowNode, TStmtParent { } /** * A C/C++ 'expression' statement. @@ -150,7 +156,7 @@ abstract class StmtParent extends ControlFlowNode { } * is an assignment expression inside an 'expression' statement. */ class ExprStmt extends Stmt, @stmt_expr { - override string getCanonicalQLClass() { result = "ExprStmt" } + override string getAPrimaryQlClass() { result = "ExprStmt" } /** * Gets the expression of this 'expression' statement. @@ -175,28 +181,32 @@ class ExprStmt extends Stmt, @stmt_expr { } } +private class TControlStructure = TConditionalStmt or TLoop; + /** * A C/C++ control structure, that is, either a conditional statement or * a loop. */ -abstract class ControlStructure extends Stmt { +class ControlStructure extends Stmt, TControlStructure { /** * Gets the controlling expression of this control structure. * * This is the condition of 'if' statements and loops, and the * switched expression for 'switch' statements. */ - abstract Expr getControllingExpr(); + Expr getControllingExpr() { none() } // overridden by subclasses /** Gets a child declaration of this scope. */ Declaration getADeclaration() { none() } } +private class TConditionalStmt = @stmt_if or @stmt_constexpr_if or @stmt_switch; + /** * A C/C++ conditional statement, that is, either an 'if' statement or a * 'switch' statement. */ -abstract class ConditionalStmt extends ControlStructure { } +class ConditionalStmt extends ControlStructure, TConditionalStmt { } /** * A C/C++ 'if' statement. For example, the `if` statement in the following @@ -208,7 +218,7 @@ abstract class ConditionalStmt extends ControlStructure { } * ``` */ class IfStmt extends ConditionalStmt, @stmt_if { - override string getCanonicalQLClass() { result = "IfStmt" } + override string getAPrimaryQlClass() { result = "IfStmt" } /** * Gets the condition expression of this 'if' statement. @@ -294,7 +304,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` */ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { - override string getCanonicalQLClass() { result = "ConstexprIfStmt" } + override string getAPrimaryQlClass() { result = "ConstexprIfStmt" } /** * Gets the condition expression of this 'constexpr if' statement. @@ -370,16 +380,18 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { } } +private class TLoop = @stmt_while or @stmt_end_test_while or @stmt_range_based_for or @stmt_for; + /** * A C/C++ loop, that is, either a 'while' loop, a 'for' loop, or a * 'do' loop. */ -abstract class Loop extends ControlStructure { +class Loop extends ControlStructure, TLoop { /** Gets the condition expression of this loop. */ - abstract Expr getCondition(); + Expr getCondition() { none() } // overridden in subclasses /** Gets the body statement of this loop. */ - abstract Stmt getStmt(); + Stmt getStmt() { none() } // overridden in subclasses } /** @@ -393,7 +405,7 @@ abstract class Loop extends ControlStructure { * ``` */ class WhileStmt extends Loop, @stmt_while { - override string getCanonicalQLClass() { result = "WhileStmt" } + override string getAPrimaryQlClass() { result = "WhileStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -457,8 +469,8 @@ class WhileStmt extends Loop, @stmt_while { /** * A C/C++ jump statement. */ -abstract class JumpStmt extends Stmt, @jump { - override string getCanonicalQLClass() { result = "JumpStmt" } +class JumpStmt extends Stmt, @jump { + override string getAPrimaryQlClass() { result = "JumpStmt" } /** Gets the target of this jump statement. */ Stmt getTarget() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -475,7 +487,7 @@ abstract class JumpStmt extends Stmt, @jump { * ``` */ class GotoStmt extends JumpStmt, @stmt_goto { - override string getCanonicalQLClass() { result = "GotoStmt" } + override string getAPrimaryQlClass() { result = "GotoStmt" } /** * Gets the name of the label this 'goto' statement refers to. @@ -570,7 +582,7 @@ class ComputedGotoStmt extends Stmt, @stmt_assigned_goto { * ``` */ class ContinueStmt extends JumpStmt, @stmt_continue { - override string getCanonicalQLClass() { result = "ContinueStmt" } + override string getAPrimaryQlClass() { result = "ContinueStmt" } override string toString() { result = "continue;" } @@ -602,7 +614,7 @@ private Stmt getEnclosingContinuable(Stmt s) { * ``` */ class BreakStmt extends JumpStmt, @stmt_break { - override string getCanonicalQLClass() { result = "BreakStmt" } + override string getAPrimaryQlClass() { result = "BreakStmt" } override string toString() { result = "break;" } @@ -635,7 +647,7 @@ private Stmt getEnclosingBreakable(Stmt s) { * ``` */ class LabelStmt extends Stmt, @stmt_label { - override string getCanonicalQLClass() { result = "LabelStmt" } + override string getAPrimaryQlClass() { result = "LabelStmt" } /** Gets the name of this 'label' statement. */ string getName() { jumpinfo(underlyingElement(this), result, _) and result != "" } @@ -663,7 +675,7 @@ class LabelStmt extends Stmt, @stmt_label { * ``` */ class ReturnStmt extends Stmt, @stmt_return { - override string getCanonicalQLClass() { result = "ReturnStmt" } + override string getAPrimaryQlClass() { result = "ReturnStmt" } /** * Gets the expression of this 'return' statement. @@ -711,7 +723,7 @@ class ReturnStmt extends Stmt, @stmt_return { * ``` */ class DoStmt extends Loop, @stmt_end_test_while { - override string getCanonicalQLClass() { result = "DoStmt" } + override string getAPrimaryQlClass() { result = "DoStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -760,7 +772,7 @@ class DoStmt extends Loop, @stmt_end_test_while { * where `begin_expr` and `end_expr` depend on the type of `xs`. */ class RangeBasedForStmt extends Loop, @stmt_range_based_for { - override string getCanonicalQLClass() { result = "RangeBasedForStmt" } + override string getAPrimaryQlClass() { result = "RangeBasedForStmt" } /** * Gets the 'body' statement of this range-based 'for' statement. @@ -847,7 +859,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` */ class ForStmt extends Loop, @stmt_for { - override string getCanonicalQLClass() { result = "ForStmt" } + override string getAPrimaryQlClass() { result = "ForStmt" } /** * Gets the initialization statement of this 'for' statement. @@ -1078,7 +1090,7 @@ private predicate inForUpdate(Expr forUpdate, Expr child) { * ``` */ class SwitchCase extends Stmt, @stmt_switch_case { - override string getCanonicalQLClass() { result = "SwitchCase" } + override string getAPrimaryQlClass() { result = "SwitchCase" } /** * Gets the expression of this 'switch case' statement (or the start of @@ -1431,7 +1443,7 @@ class DefaultCase extends SwitchCase { * ``` */ class SwitchStmt extends ConditionalStmt, @stmt_switch { - override string getCanonicalQLClass() { result = "SwitchStmt" } + override string getAPrimaryQlClass() { result = "SwitchStmt" } /** * Gets the expression that this 'switch' statement switches on. @@ -1455,7 +1467,7 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch { /** * Gets the body statement of this 'switch' statement. * - * In almost all cases the result will be a `BlockStmt`, but there are + * In almost all cases the result will be a `Block`, but there are * other syntactically valid constructions. * * For example, for @@ -1642,7 +1654,7 @@ class EnumSwitch extends SwitchStmt { class Handler extends Stmt, @stmt_handler { override string toString() { result = "" } - override string getCanonicalQLClass() { result = "Handler" } + override string getAPrimaryQlClass() { result = "Handler" } /** * Gets the block containing the implementation of this handler. @@ -1695,7 +1707,7 @@ deprecated class FinallyEnd extends Stmt { * ``` */ class TryStmt extends Stmt, @stmt_try_block { - override string getCanonicalQLClass() { result = "TryStmt" } + override string getAPrimaryQlClass() { result = "TryStmt" } override string toString() { result = "try { ... }" } @@ -1770,7 +1782,7 @@ class TryStmt extends Stmt, @stmt_try_block { class FunctionTryStmt extends TryStmt { FunctionTryStmt() { not exists(this.getEnclosingBlock()) } - override string getCanonicalQLClass() { result = "FunctionTryStmt" } + override string getAPrimaryQlClass() { result = "FunctionTryStmt" } } /** @@ -1787,7 +1799,7 @@ class FunctionTryStmt extends TryStmt { * ``` */ class CatchBlock extends Block { - override string getCanonicalQLClass() { result = "CatchBlock" } + override string getAPrimaryQlClass() { result = "CatchBlock" } CatchBlock() { ishandler(underlyingElement(this)) } @@ -1818,7 +1830,7 @@ class CatchBlock extends Block { class CatchAnyBlock extends CatchBlock { CatchAnyBlock() { not exists(this.getParameter()) } - override string getCanonicalQLClass() { result = "CatchAnyBlock" } + override string getAPrimaryQlClass() { result = "CatchAnyBlock" } } /** @@ -1855,7 +1867,7 @@ class MicrosoftTryExceptStmt extends MicrosoftTryStmt { /** Gets the `__except` statement (usually a `Block`). */ Stmt getExcept() { result = getChild(2) } - override string getCanonicalQLClass() { result = "MicrosoftTryExceptStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryExceptStmt" } } /** @@ -1879,7 +1891,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { /** Gets the `__finally` statement (usually a `Block`). */ Stmt getFinally() { result = getChild(1) } - override string getCanonicalQLClass() { result = "MicrosoftTryFinallyStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryFinallyStmt" } } /** @@ -1891,7 +1903,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { * ``` */ class DeclStmt extends Stmt, @stmt_decl { - override string getCanonicalQLClass() { result = "DeclStmt" } + override string getAPrimaryQlClass() { result = "DeclStmt" } /** * Gets the `i`th declaration entry declared by this 'declaration' statement. @@ -1972,7 +1984,7 @@ class DeclStmt extends Stmt, @stmt_decl { * ``` */ class EmptyStmt extends Stmt, @stmt_empty { - override string getCanonicalQLClass() { result = "EmptyStmt" } + override string getAPrimaryQlClass() { result = "EmptyStmt" } override string toString() { result = ";" } @@ -1992,7 +2004,7 @@ class EmptyStmt extends Stmt, @stmt_empty { class AsmStmt extends Stmt, @stmt_asm { override string toString() { result = "asm statement" } - override string getCanonicalQLClass() { result = "AsmStmt" } + override string getAPrimaryQlClass() { result = "AsmStmt" } } /** @@ -2009,7 +2021,7 @@ class AsmStmt extends Stmt, @stmt_asm { class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { override string toString() { result = "VLA dimension size" } - override string getCanonicalQLClass() { result = "VlaDimensionStmt" } + override string getAPrimaryQlClass() { result = "VlaDimensionStmt" } /** Gets the expression which gives the size. */ Expr getDimensionExpr() { result = this.getChild(0) } @@ -2028,7 +2040,7 @@ class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { class VlaDeclStmt extends Stmt, @stmt_vla_decl { override string toString() { result = "VLA declaration" } - override string getCanonicalQLClass() { result = "VlaDeclStmt" } + override string getAPrimaryQlClass() { result = "VlaDeclStmt" } /** * Gets the number of VLA dimension statements in this VLA diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 874439f4c50..025827d85c3 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -420,7 +420,7 @@ function_deleted(unique int id: @function ref); function_defaulted(unique int id: @function ref); - +member_function_this_type(unique int id: @function ref, int this_type: @type ref); #keyset[id, type_id] fun_decls( @@ -1143,6 +1143,13 @@ conversionkinds( int kind: int ref ); +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + /* case @funbindexpr.kind of 0 = @normal_call // a normal call @@ -1641,6 +1648,67 @@ case @expr.kind of | 326 = @spaceshipexpr ; +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + new_allocated_type( unique int expr: @new_expr ref, int type_id: @type ref @@ -1739,6 +1807,8 @@ lambda_capture( @addressable = @function | @variable ; @accessible = @addressable | @enumconstant ; +@access = @varaccess | @routineexpr ; + fold( int expr: @foldexpr ref, string operator: string ref, diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 193ba78890d..5a46cae4c17 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -9552 +9550 @externalDataElement @@ -25,7 +25,7 @@ @location_default -8813337 +8812005 @location_stmt @@ -37,43 +37,43 @@ @diagnostic -68696 +68684 @file -60022 +60011 @folder -10945 +10943 @macroinvocation -35579091 +35573550 @function -3468206 +3467595 @fun_decl -3540511 +3539887 @var_decl -5359926 +5359092 @type_decl -1332120 +1331886 @namespace_decl -136867 +136843 @using -291435 +291384 @static_assert @@ -81,11 +81,11 @@ @parameter -4627839 +4627024 @membervariable -305681 +305627 @globalvariable @@ -101,23 +101,23 @@ @builtintype -504 +515 @derivedtype -4417712 +4630204 @decltype -47004 +46996 @usertype -4193822 +4193084 @mangledname -483674 +483589 @type_mention @@ -125,19 +125,19 @@ @routinetype -430474 +430398 @ptrtomember -12633 +12631 @specifier -493 +504 @gnuattribute -413159 +413730 @stdattribute @@ -145,7 +145,7 @@ @declspec -57808 +57828 @msattribute @@ -153,7 +153,7 @@ @alignas -252 +1743 @attribute_arg_empty @@ -165,7 +165,7 @@ @attribute_arg_constant -145712 +146276 @attribute_arg_type @@ -173,19 +173,19 @@ @derivation -390258 +390189 @frienddecl -240340 +240298 @comment -1580291 +1580013 @namespace -7687 +7686 @specialnamequalifyingelement @@ -205,7 +205,7 @@ @errorexpr -48715 +48706 @address_of @@ -213,7 +213,7 @@ @reference_to -1057881 +1058090 @indirect @@ -221,7 +221,7 @@ @ref_indirect -1253827 +1253936 @array_to_pointer @@ -229,7 +229,7 @@ @vacuous_destructor_call -5121 +5120 @assume @@ -277,11 +277,11 @@ @preincrexpr -62522 +62511 @predecrexpr -24796 +24791 @conditionalexpr @@ -341,7 +341,7 @@ @pdiffexpr -25081 +25076 @lshiftexpr @@ -377,7 +377,7 @@ @ltexpr -51742 +51732 @geexpr @@ -409,7 +409,7 @@ @assignmulexpr -6909 +6907 @assigndivexpr @@ -457,7 +457,7 @@ @commaexpr -10725 +10734 @subscriptexpr @@ -469,7 +469,7 @@ @callexpr -226829 +226789 @vastartexpr @@ -477,7 +477,7 @@ @vaargexpr -987 +986 @vaendexpr @@ -497,19 +497,19 @@ @new_expr -32133 +32127 @delete_expr -5966 +5964 @throw_expr -22317 +22313 @condition_decl -7007 +7028 @braced_init_list @@ -517,7 +517,7 @@ @type_id -4419 +4418 @runtime_sizeof @@ -537,7 +537,7 @@ @routineexpr -2265747 +2265918 @type_operand @@ -661,15 +661,15 @@ @ctordirectinit -90192 +90176 @ctorvirtualinit -6229 +6228 @ctorfieldinit -196044 +196010 @ctordelegatinginit @@ -677,7 +677,7 @@ @dtordirectdestruct -29139 +29134 @dtorvirtualdestruct @@ -685,11 +685,11 @@ @dtorfielddestruct -29906 +29901 @static_cast -214754 +214716 @reinterpret_cast @@ -701,7 +701,7 @@ @dynamic_cast -987 +986 @c_style_cast @@ -713,7 +713,7 @@ @param_ref -85893 +85877 @noopexpr @@ -817,7 +817,7 @@ @noexceptexpr -17525 +17522 @builtinshufflevector @@ -829,7 +829,7 @@ @builtinaddressof -3970 +3969 @vec_fill @@ -861,7 +861,7 @@ @stmt_while -30992 +30998 @stmt_goto @@ -873,11 +873,11 @@ @stmt_return -1130186 +1130009 @stmt_block -1325091 +1325000 @stmt_end_test_while @@ -901,7 +901,7 @@ @stmt_try_block -17963 +17960 @stmt_microsoft_try @@ -909,7 +909,7 @@ @stmt_decl -613073 +613064 @stmt_set_vla_size @@ -949,39 +949,39 @@ @ppd_if -156092 +156064 @ppd_ifdef -61085 +61075 @ppd_ifndef -83326 +83312 @ppd_elif -20628 +20625 @ppd_else -57664 +57654 @ppd_endif -300505 +300452 @ppd_plain_include -290755 +290704 @ppd_define -318063 +318007 @ppd_undef -19246 +19243 @ppd_line @@ -1038,11 +1038,11 @@ compilations -9552 +9550 id -9552 +9550 cwd @@ -1060,7 +1060,7 @@ 1 2 -9552 +9550 @@ -1382,11 +1382,11 @@ compilation_compiling_files -9552 +9550 id -9552 +9550 num @@ -1394,7 +1394,7 @@ file -4847 +4846 @@ -1408,7 +1408,7 @@ 1 2 -9552 +9550 @@ -1424,7 +1424,7 @@ 1 2 -9552 +9550 @@ -1477,7 +1477,7 @@ 2 3 -4551 +4550 3 @@ -1498,7 +1498,7 @@ 1 2 -4847 +4846 @@ -1508,11 +1508,11 @@ compilation_time -38121 +38114 id -9530 +9528 num @@ -1524,7 +1524,7 @@ seconds -13522 +12390 @@ -1538,7 +1538,7 @@ 1 2 -9530 +9528 @@ -1554,7 +1554,7 @@ 4 5 -9530 +9528 @@ -1570,12 +1570,12 @@ 3 4 -3158 +2576 4 5 -6371 +6951 @@ -1621,8 +1621,8 @@ 12 -1233 -1234 +1130 +1131 10 @@ -1669,23 +1669,23 @@ 12 -8 -9 +7 +8 10 -13 -14 +14 +15 10 -646 -647 +582 +583 10 -735 -736 +658 +659 10 @@ -1702,22 +1702,22 @@ 1 2 -9409 +8355 2 3 -2972 +2379 3 -9 -1019 +4 +899 -9 -615 -120 +4 +646 +756 @@ -1733,7 +1733,7 @@ 1 2 -13522 +12390 @@ -1749,17 +1749,12 @@ 1 2 -11679 +10954 2 3 -1831 - - -3 -4 -10 +1436 @@ -1769,15 +1764,15 @@ diagnostic_for -847086 +846937 diagnostic -68696 +68684 compilation -9223 +9221 file_number @@ -1785,7 +1780,7 @@ file_number_diagnostic_number -6503 +6502 @@ -1799,12 +1794,12 @@ 1 2 -9256 +9254 2 3 -56742 +56732 254 @@ -1825,7 +1820,7 @@ 1 2 -68696 +68684 @@ -1841,7 +1836,7 @@ 1 2 -68696 +68684 @@ -1862,7 +1857,7 @@ 7 8 -5812 +5811 8 @@ -1898,7 +1893,7 @@ 1 2 -9223 +9221 @@ -1919,7 +1914,7 @@ 7 8 -5812 +5811 8 @@ -2013,7 +2008,7 @@ 5 6 -954 +953 7 @@ -2064,7 +2059,7 @@ 10 11 -954 +953 14 @@ -2099,7 +2094,7 @@ 254 255 -2621 +2620 309 @@ -2120,7 +2115,7 @@ 1 2 -6503 +6502 @@ -2130,19 +2125,19 @@ compilation_finished -9552 +9550 id -9552 +9550 cpu_seconds -8587 +7993 elapsed_seconds -219 +197 @@ -2156,7 +2151,7 @@ 1 2 -9552 +9550 @@ -2172,7 +2167,7 @@ 1 2 -9552 +9550 @@ -2188,17 +2183,17 @@ 1 2 -7797 +6864 2 3 -668 +855 3 -7 -120 +8 +274 @@ -2214,12 +2209,12 @@ 1 2 -8389 +7500 2 3 -197 +493 @@ -2235,7 +2230,7 @@ 1 2 -54 +32 2 @@ -2243,14 +2238,9 @@ 32 -5 -6 -10 - - -6 -7 -10 +3 +4 +21 9 @@ -2258,8 +2248,8 @@ 10 -11 -12 +12 +13 10 @@ -2268,38 +2258,38 @@ 10 -37 -38 +26 +27 10 -52 -53 +38 +39 10 -78 -79 +99 +100 10 -91 -92 +100 +101 10 -156 -157 +140 +141 10 -166 -167 +195 +196 10 -233 -234 +221 +222 10 @@ -2316,7 +2306,7 @@ 1 2 -54 +32 2 @@ -2324,14 +2314,9 @@ 32 -5 -6 -10 - - -6 -7 -10 +3 +4 +21 9 @@ -2349,33 +2334,38 @@ 10 -36 -37 +25 +26 10 -51 -52 +37 +38 10 -74 -75 -21 - - -147 -148 +77 +78 10 -157 -158 +89 +90 10 -204 -205 +134 +135 +10 + + +176 +177 +10 + + +185 +186 10 @@ -5279,11 +5269,11 @@ header_to_external_package -8532 +8530 fileid -8532 +8530 package @@ -5301,7 +5291,7 @@ 1 2 -8532 +8530 @@ -6570,31 +6560,31 @@ locations_default -8813337 +8812005 id -8813337 +8812005 container -70967 +70954 startLine -150630 +150604 startColumn -5461 +5460 endLine -150455 +150428 endColumn -10626 +10625 @@ -6608,7 +6598,7 @@ 1 2 -8813337 +8812005 @@ -6624,7 +6614,7 @@ 1 2 -8813337 +8812005 @@ -6640,7 +6630,7 @@ 1 2 -8813337 +8812005 @@ -6656,7 +6646,7 @@ 1 2 -8813337 +8812005 @@ -6672,7 +6662,7 @@ 1 2 -8813337 +8812005 @@ -6688,62 +6678,62 @@ 1 2 -11526 +11524 2 19 -6097 +6096 19 25 -5483 +5482 25 31 -5516 +5515 31 41 -5823 +5822 41 54 -5527 +5526 54 72 -5604 +5603 72 99 -5417 +5416 99 137 -5384 +5383 137 220 -5329 +5328 220 430 -5329 +5328 430 20913 -3926 +3925 @@ -6759,57 +6749,57 @@ 1 2 -11526 +11524 2 15 -6009 +6008 15 20 -6141 +6140 20 25 -5549 +5548 25 32 -6097 +6096 32 41 -5680 +5679 41 53 -5724 +5723 53 71 -5593 +5592 71 99 -5450 +5449 99 158 -5329 +5328 158 351 -5362 +5361 351 @@ -6830,57 +6820,57 @@ 1 2 -11526 +11524 2 4 -6009 +6008 4 8 -6547 +6546 8 11 -5395 +5394 11 14 -5779 +5778 14 18 -6251 +6250 18 23 -5757 +5756 23 29 -5834 +5833 29 37 -5691 +5690 37 50 -5669 +5668 50 78 -5384 +5383 78 @@ -6901,57 +6891,57 @@ 1 2 -11526 +11524 2 15 -5987 +5986 15 20 -6163 +6162 20 25 -5494 +5493 25 32 -6108 +6107 32 41 -5669 +5668 41 53 -5724 +5723 53 70 -5384 +5383 70 96 -5340 +5339 96 153 -5395 +5394 153 333 -5351 +5350 333 @@ -6972,57 +6962,57 @@ 1 2 -11526 +11524 2 14 -5735 +5734 14 19 -6119 +6118 19 23 -5713 +5712 23 28 -6415 +6414 28 33 -5516 +5515 33 40 -5955 +5953 40 47 -5351 +5350 47 57 -5604 +5603 57 69 -5637 +5636 69 91 -5329 +5328 91 @@ -7043,52 +7033,52 @@ 1 2 -30849 +30844 2 3 -18029 +18026 3 4 -17952 +17949 4 5 -9716 +9714 5 7 -13708 +13706 7 9 -13412 +13410 9 13 -13204 +13201 13 32 -11570 +11568 32 127 -11306 +11304 127 6472 -10879 +10877 @@ -7104,42 +7094,42 @@ 1 2 -55657 +55647 2 3 -33438 +33432 3 4 -9903 +9901 4 5 -8433 +8432 5 8 -12908 +12905 8 27 -11493 +11491 27 123 -11339 +11337 123 6472 -7457 +7456 @@ -7155,52 +7145,52 @@ 1 2 -31957 +31952 2 3 -17865 +17861 3 4 -19795 +19791 4 5 -9585 +9583 5 7 -13917 +13914 7 9 -13829 +13826 9 13 -12710 +12708 13 27 -11482 +11480 27 62 -11350 +11348 62 153 -8137 +8136 @@ -7216,22 +7206,22 @@ 1 2 -112970 +112950 2 3 -17415 +17412 3 7 -12535 +12533 7 184 -7709 +7708 @@ -7247,52 +7237,52 @@ 1 2 -31804 +31798 2 3 -17777 +17774 3 4 -18643 +18640 4 5 -9870 +9868 5 7 -13730 +13728 7 9 -13774 +13772 9 13 -12732 +12730 13 29 -11657 +11655 29 74 -11350 +11348 74 258 -9288 +9287 @@ -7613,52 +7603,52 @@ 1 2 -30564 +30559 2 3 -18062 +18059 3 4 -17810 +17807 4 5 -9870 +9868 5 7 -13774 +13772 7 9 -13456 +13454 9 13 -13050 +13048 13 31 -11460 +11458 31 124 -11295 +11293 124 6472 -11109 +11107 @@ -7674,42 +7664,42 @@ 1 2 -55372 +55362 2 3 -33339 +33333 3 4 -9870 +9868 4 5 -8543 +8541 5 8 -13105 +13103 8 27 -11328 +11326 27 121 -11295 +11293 121 6472 -7600 +7598 @@ -7725,22 +7715,22 @@ 1 2 -112180 +112161 2 3 -17250 +17247 3 7 -12074 +12072 7 46 -8949 +8947 @@ -7756,57 +7746,57 @@ 1 2 -31650 +31645 2 3 -17941 +17938 3 4 -19740 +19737 4 5 -9607 +9605 5 6 -7863 +7861 6 7 -6130 +6129 7 9 -13840 +13837 9 13 -12710 +12708 13 27 -11493 +11491 27 62 -11350 +11348 62 153 -8126 +8125 @@ -7822,52 +7812,52 @@ 1 2 -31551 +31546 2 3 -17744 +17741 3 4 -18632 +18629 4 5 -9936 +9934 5 7 -13818 +13815 7 9 -13774 +13772 9 13 -12787 +12785 13 29 -11515 +11513 29 74 -11361 +11359 74 258 -9332 +9331 @@ -7883,7 +7873,7 @@ 1 2 -4211 +4210 2 @@ -7898,7 +7888,7 @@ 4 5 -647 +646 5 @@ -7921,7 +7911,7 @@ 800 -7760 +7763 25755 526 @@ -7939,17 +7929,17 @@ 1 2 -4836 +4835 2 3 -1283 +1282 3 4 -954 +953 4 @@ -7990,7 +7980,7 @@ 1 2 -4244 +4243 2 @@ -8005,7 +7995,7 @@ 4 5 -636 +635 5 @@ -8046,7 +8036,7 @@ 1 2 -4869 +4868 2 @@ -8056,7 +8046,7 @@ 3 4 -943 +942 4 @@ -8097,7 +8087,7 @@ 1 2 -4244 +4243 2 @@ -8112,7 +8102,7 @@ 4 5 -636 +635 5 @@ -11616,23 +11606,23 @@ numlines -499247 +499159 element_id -492283 +492197 num_lines -9343 +9342 num_code -7293 +7291 num_comment -3937 +3936 @@ -11646,12 +11636,12 @@ 1 2 -485396 +485311 2 7 -6887 +6886 @@ -11667,12 +11657,12 @@ 1 2 -485451 +485366 2 7 -6832 +6831 @@ -11688,7 +11678,7 @@ 1 2 -492207 +492120 2 @@ -11709,7 +11699,7 @@ 1 2 -4255 +4254 2 @@ -11765,7 +11755,7 @@ 2 3 -1261 +1260 3 @@ -11811,12 +11801,12 @@ 1 2 -4310 +4309 2 3 -1261 +1260 3 @@ -11857,7 +11847,7 @@ 1 2 -3180 +3179 2 @@ -11892,7 +11882,7 @@ 101 7978 -329 +328 @@ -11908,7 +11898,7 @@ 1 2 -3202 +3201 2 @@ -11918,7 +11908,7 @@ 3 4 -636 +635 4 @@ -11928,7 +11918,7 @@ 6 10 -636 +635 10 @@ -11959,7 +11949,7 @@ 1 2 -3191 +3190 2 @@ -11969,7 +11959,7 @@ 3 4 -636 +635 4 @@ -11994,7 +11984,7 @@ 27 34 -318 +317 @@ -12010,7 +12000,7 @@ 1 2 -1886 +1885 2 @@ -12025,12 +12015,12 @@ 4 7 -329 +328 7 13 -329 +328 14 @@ -12061,7 +12051,7 @@ 1 2 -1897 +1896 2 @@ -12081,7 +12071,7 @@ 7 13 -329 +328 13 @@ -12112,7 +12102,7 @@ 1 2 -1897 +1896 2 @@ -12127,7 +12117,7 @@ 4 7 -329 +328 7 @@ -12157,11 +12147,11 @@ diagnostics -68696 +68684 id -68696 +68684 severity @@ -12177,7 +12167,7 @@ full_error_message -59484 +59474 location @@ -12195,7 +12185,7 @@ 1 2 -68696 +68684 @@ -12211,7 +12201,7 @@ 1 2 -68696 +68684 @@ -12227,7 +12217,7 @@ 1 2 -68696 +68684 @@ -12243,7 +12233,7 @@ 1 2 -68696 +68684 @@ -12259,7 +12249,7 @@ 1 2 -68696 +68684 @@ -12675,7 +12665,7 @@ 1 2 -59473 +59463 841 @@ -12696,7 +12686,7 @@ 1 2 -59484 +59474 @@ -12712,7 +12702,7 @@ 1 2 -59484 +59474 @@ -12728,7 +12718,7 @@ 1 2 -59484 +59474 @@ -12744,7 +12734,7 @@ 1 2 -59484 +59474 @@ -12854,19 +12844,19 @@ files -60022 +60011 id -60022 +60011 name -60022 +60011 simple -41060 +41052 ext @@ -12888,7 +12878,7 @@ 1 2 -60022 +60011 @@ -12904,7 +12894,7 @@ 1 2 -60022 +60011 @@ -12920,7 +12910,7 @@ 1 2 -60022 +60011 @@ -12936,7 +12926,7 @@ 1 2 -60022 +60011 @@ -12952,7 +12942,7 @@ 1 2 -60022 +60011 @@ -12968,7 +12958,7 @@ 1 2 -60022 +60011 @@ -12984,7 +12974,7 @@ 1 2 -60022 +60011 @@ -13000,7 +12990,7 @@ 1 2 -60022 +60011 @@ -13016,17 +13006,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13047,17 +13037,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13078,12 +13068,12 @@ 1 2 -36706 +36699 2 3 -3783 +3782 3 @@ -13104,7 +13094,7 @@ 1 2 -41060 +41052 @@ -13362,19 +13352,19 @@ folders -10945 +10943 id -10945 +10943 name -10945 +10943 simple -3136 +3135 @@ -13388,7 +13378,7 @@ 1 2 -10945 +10943 @@ -13404,7 +13394,7 @@ 1 2 -10945 +10943 @@ -13420,7 +13410,7 @@ 1 2 -10945 +10943 @@ -13436,7 +13426,7 @@ 1 2 -10945 +10943 @@ -13518,15 +13508,15 @@ containerparent -70945 +70932 parent -10945 +10943 child -70945 +70932 @@ -13591,7 +13581,7 @@ 1 2 -70945 +70932 @@ -13601,11 +13591,11 @@ fileannotations -5150534 +5149627 id -4825 +4824 kind @@ -13613,11 +13603,11 @@ name -54626 +54616 value -44646 +44638 @@ -13852,42 +13842,42 @@ 1 2 -8927 +8925 2 3 -6031 +6030 3 6 -4518 +4517 6 8 -4452 +4451 8 14 -4408 +4407 14 18 -3915 +3914 18 21 -4244 +4243 21 34 -4397 +4396 34 @@ -13897,12 +13887,12 @@ 129 236 -4156 +4155 236 395 -4112 +4111 395 @@ -13923,7 +13913,7 @@ 1 2 -54626 +54616 @@ -13939,12 +13929,12 @@ 1 2 -9979 +9978 2 3 -8049 +8048 3 @@ -13954,42 +13944,42 @@ 4 6 -3959 +3958 6 10 -4880 +4879 10 14 -3487 +3486 14 18 -4496 +4495 18 23 -4200 +4199 23 44 -4397 +4396 44 97 -4156 +4155 97 405 -4101 +4100 421 @@ -14010,7 +14000,7 @@ 1 2 -6898 +6896 2 @@ -14020,7 +14010,7 @@ 5 8 -3235 +3234 8 @@ -14040,17 +14030,17 @@ 25 40 -3235 +3234 40 195 -3520 +3519 195 207 -3509 +3508 207 @@ -14065,12 +14055,12 @@ 328 407 -3838 +3837 407 441 -1283 +1282 @@ -14086,7 +14076,7 @@ 1 2 -44635 +44627 2 @@ -14107,12 +14097,12 @@ 1 2 -6920 +6918 2 5 -2511 +2510 5 @@ -14122,7 +14112,7 @@ 8 16 -3498 +3497 16 @@ -14137,17 +14127,17 @@ 21 31 -3882 +3881 31 41 -3531 +3530 41 54 -3531 +3530 54 @@ -14458,19 +14448,19 @@ macroinvocations -35579091 +35573550 id -35579091 +35573550 macro_id -81232 +81217 location -761215 +761081 kind @@ -14488,7 +14478,7 @@ 1 2 -35579091 +35573550 @@ -14504,7 +14494,7 @@ 1 2 -35579091 +35573550 @@ -14520,7 +14510,7 @@ 1 2 -35579091 +35573550 @@ -14536,52 +14526,52 @@ 1 2 -17020 +17017 2 3 -16560 +16557 3 4 -3575 +3574 4 6 -7194 +7193 6 11 -6898 +6896 11 19 -6174 +6173 19 40 -6174 +6173 40 105 -6196 +6195 105 487 -6108 +6107 488 196960 -5329 +5328 @@ -14597,32 +14587,32 @@ 1 2 -43220 +43213 2 3 -10747 +10745 3 4 -5340 +5339 4 6 -6974 +6973 6 13 -6722 +6721 13 66 -6108 +6107 66 @@ -14643,12 +14633,12 @@ 1 2 -75090 +75077 2 3 -6141 +6140 @@ -14664,42 +14654,42 @@ 1 2 -284263 +284333 2 3 -177631 +177479 3 4 -43451 +43443 4 5 -58596 +58586 5 8 -63575 +63564 8 17 -61162 +61151 17 80 -57159 +57149 80 258137 -15375 +15372 @@ -14715,12 +14705,12 @@ 1 2 -712510 +712385 2 354 -48704 +48695 @@ -14736,7 +14726,7 @@ 1 2 -761215 +761081 @@ -14755,8 +14745,8 @@ 10 -3216528 -3216529 +3216594 +3216595 10 @@ -14809,15 +14799,15 @@ macroparent -31702256 +31697519 id -31702256 +31697519 parent_id -24679337 +24675496 @@ -14831,7 +14821,7 @@ 1 2 -31702256 +31697519 @@ -14847,17 +14837,17 @@ 1 2 -18989054 +18986039 2 3 -4852979 +4852278 3 88 -837303 +837178 @@ -14945,11 +14935,11 @@ macro_argument_unexpanded -92645581 +92630311 invocation -27418856 +27414610 argument_index @@ -14957,7 +14947,7 @@ text -312667 +312612 @@ -14971,22 +14961,22 @@ 1 2 -7656282 +7655065 2 3 -11466261 +11464681 3 4 -6261232 +6260141 4 67 -2035079 +2034721 @@ -15002,22 +14992,22 @@ 1 2 -7724233 +7723004 2 3 -11620160 +11618553 3 4 -6089819 +6088758 4 67 -1984642 +1984293 @@ -15033,7 +15023,7 @@ 50787 50788 -636 +635 50989 @@ -15041,8 +15031,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15059,7 +15049,7 @@ 2 3 -636 +635 13 @@ -15085,57 +15075,57 @@ 1 2 -37901 +37895 2 3 -61162 +61118 3 4 -14092 +14090 4 5 -42124 +42138 5 8 -25300 +25296 8 12 -15112 +15120 12 16 -21780 +21765 16 21 -23940 +23936 21 41 -24971 +24967 41 121 -23787 +23794 121 567376 -22493 +22489 @@ -15151,17 +15141,17 @@ 1 2 -226061 +226021 2 3 -76307 +76294 3 9 -10297 +10296 @@ -15171,11 +15161,11 @@ macro_argument_expanded -92645581 +92630311 invocation -27418856 +27414610 argument_index @@ -15183,7 +15173,7 @@ text -189442 +189409 @@ -15197,22 +15187,22 @@ 1 2 -7656282 +7655065 2 3 -11466261 +11464681 3 4 -6261232 +6260141 4 67 -2035079 +2034721 @@ -15228,22 +15218,22 @@ 1 2 -11164682 +11162979 2 3 -9894184 +9892749 3 4 -5269679 +5268762 4 9 -1090310 +1090118 @@ -15259,7 +15249,7 @@ 50787 50788 -636 +635 50989 @@ -15267,8 +15257,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15311,62 +15301,62 @@ 1 2 -22866 +22862 2 3 -38219 +38180 3 4 -6240 +6239 4 5 -15167 +15186 5 6 -2763 +2752 6 7 -22032 +22039 7 9 -15463 +15471 9 15 -16494 +16480 15 28 -14257 +14254 28 77 -14322 +14331 77 337 -14322 +14320 338 -1133296 -7293 +1133308 +7291 @@ -15382,17 +15372,17 @@ 1 2 -95631 +95614 2 3 -79488 +79474 3 6 -14246 +14243 6 @@ -15407,15 +15397,15 @@ functions -3468206 +3467595 id -3468206 +3467595 name -288386 +288335 kind @@ -15433,7 +15423,7 @@ 1 2 -3468206 +3467595 @@ -15449,7 +15439,7 @@ 1 2 -3468206 +3467595 @@ -15465,27 +15455,27 @@ 1 2 -195397 +195363 2 3 -28316 +28311 3 5 -26079 +26074 5 13 -22164 +22160 13 123517 -16428 +16425 @@ -15501,7 +15491,7 @@ 1 2 -286927 +286877 2 @@ -15608,15 +15598,15 @@ function_entry_point -1008530 +1008374 id -1005602 +1005447 entry_point -1008530 +1008374 @@ -15630,7 +15620,7 @@ 1 2 -1002948 +1002793 2 @@ -15651,7 +15641,7 @@ 1 2 -1008530 +1008374 @@ -15661,15 +15651,15 @@ function_return_type -3478372 +3477760 id -3467734 +3467124 return_type -1023555 +1023375 @@ -15683,12 +15673,12 @@ 1 2 -3457590 +3456981 2 6 -10144 +10142 @@ -15704,17 +15694,17 @@ 1 2 -299156 +299103 2 3 -662688 +662571 3 84263 -61710 +61700 @@ -15735,49 +15725,132 @@ function_deleted -56183 +56173 id -56183 +56173 function_defaulted -12930 +12927 id -12930 +12927 -fun_decls -3543779 +member_function_this_type +523250 id -3540511 +522921 + + +this_type +171339 + + + + +id +this_type + + +12 + + +1 +2 +522592 + + +2 +3 +328 + + + + + + +this_type +id + + +12 + + +1 +2 +62533 + + +2 +3 +44550 + + +3 +4 +22291 + + +4 +5 +15011 + + +5 +7 +13684 + + +7 +36 +12872 + + +40 +87 +394 + + + + + + + + +fun_decls +3543155 + + +id +3539887 function -3374756 +3374162 type_id -1010482 +1010304 name -256834 +256789 location -795431 +795291 @@ -15791,7 +15864,7 @@ 1 2 -3540511 +3539887 @@ -15807,12 +15880,12 @@ 1 2 -3537528 +3536905 2 4 -2983 +2982 @@ -15828,7 +15901,7 @@ 1 2 -3540511 +3539887 @@ -15844,7 +15917,7 @@ 1 2 -3540511 +3539887 @@ -15860,12 +15933,12 @@ 1 2 -3238733 +3238163 2 9 -136022 +135998 @@ -15881,12 +15954,12 @@ 1 2 -3358098 +3357506 2 6 -16658 +16655 @@ -15902,7 +15975,7 @@ 1 2 -3374756 +3374162 @@ -15918,12 +15991,12 @@ 1 2 -3287120 +3286541 2 9 -87636 +87621 @@ -15939,17 +16012,17 @@ 1 2 -280325 +280276 2 3 -661065 +660948 3 89606 -69091 +69079 @@ -15965,17 +16038,17 @@ 1 2 -292159 +292107 2 3 -657413 +657297 3 83378 -60910 +60899 @@ -15991,12 +16064,12 @@ 1 2 -943946 +943780 2 7512 -66536 +66524 @@ -16012,17 +16085,17 @@ 1 2 -913085 +912924 2 6 -80146 +80132 6 22467 -17250 +17247 @@ -16038,32 +16111,32 @@ 1 2 -153548 +153521 2 3 -29303 +29298 3 4 -15934 +15932 4 6 -19521 +19517 6 13 -20201 +20197 13 123766 -18325 +18322 @@ -16079,32 +16152,32 @@ 1 2 -164175 +164146 2 3 -28481 +28476 3 4 -14454 +14451 4 7 -21637 +21633 7 25 -19641 +19638 25 123501 -8444 +8443 @@ -16120,17 +16193,17 @@ 1 2 -224328 +224289 2 5 -20870 +20866 5 63265 -11635 +11633 @@ -16146,27 +16219,27 @@ 1 2 -164668 +164639 2 3 -43461 +43454 3 4 -16439 +16436 4 8 -20573 +20570 8 8921 -11690 +11688 @@ -16182,27 +16255,27 @@ 1 2 -522750 +522657 2 3 -143886 +143860 3 5 -64858 +64847 5 125 -59693 +59682 125 3043 -4244 +4243 @@ -16218,22 +16291,22 @@ 1 2 -537676 +537581 2 3 -156849 +156821 3 9 -64343 +64331 9 3043 -36563 +36557 @@ -16249,17 +16322,17 @@ 1 2 -701785 +701661 2 4 -61787 +61776 4 1522 -31858 +31853 @@ -16275,12 +16348,12 @@ 1 2 -770427 +770291 2 134 -25004 +25000 @@ -16290,11 +16363,11 @@ fun_def -1230764 +1230547 id -1230764 +1230547 @@ -16517,26 +16590,26 @@ fun_decl_empty_throws -1420942 +1420692 fun_decl -1420942 +1420692 fun_decl_noexcept -32911 +32905 fun_decl -32122 +32116 constant -32791 +32785 @@ -16550,7 +16623,7 @@ 1 2 -31332 +31327 2 @@ -16571,7 +16644,7 @@ 1 2 -32670 +32664 2 @@ -16586,11 +16659,11 @@ fun_decl_empty_noexcept -391947 +391878 fun_decl -391947 +391878 @@ -16645,11 +16718,11 @@ param_decl_bind -4651385 +4650566 id -4651385 +4650566 index @@ -16657,7 +16730,7 @@ fun_decl -3071663 +3071122 @@ -16671,7 +16744,7 @@ 1 2 -4651385 +4650566 @@ -16687,7 +16760,7 @@ 1 2 -4651385 +4650566 @@ -16785,22 +16858,22 @@ 1 2 -2195218 +2194832 2 3 -478564 +478479 3 4 -242709 +242666 4 65 -155171 +155143 @@ -16816,22 +16889,22 @@ 1 2 -2195218 +2194832 2 3 -478564 +478479 3 4 -242709 +242666 4 65 -155171 +155143 @@ -16841,27 +16914,27 @@ var_decls -5368776 +5367940 id -5359926 +5359092 variable -5132044 +5131261 type_id -2007706 +2007363 name -126306 +126283 location -1232409 +1232192 @@ -16875,7 +16948,7 @@ 1 2 -5359926 +5359092 @@ -16891,12 +16964,12 @@ 1 2 -5351262 +5350429 2 4 -8663 +8662 @@ -16912,7 +16985,7 @@ 1 2 -5359926 +5359092 @@ -16928,7 +17001,7 @@ 1 2 -5359882 +5359048 2 @@ -16949,12 +17022,12 @@ 1 2 -4944542 +4943803 2 9 -187501 +187457 @@ -16970,12 +17043,12 @@ 1 2 -5096697 +5095931 2 7 -35346 +35329 @@ -16991,12 +17064,12 @@ 1 2 -5114475 +5113695 2 3 -17569 +17565 @@ -17012,12 +17085,12 @@ 1 2 -5023833 +5023069 2 9 -108210 +108191 @@ -17033,22 +17106,22 @@ 1 2 -1580818 +1580539 2 3 -228879 +228850 3 11 -156958 +156942 11 5924 -41049 +41031 @@ -17064,22 +17137,22 @@ 1 2 -1605011 +1604728 2 3 -219645 +219618 3 13 -151135 +151108 13 5424 -31913 +31908 @@ -17095,17 +17168,17 @@ 1 2 -1832849 +1832537 2 5 -151245 +151207 5 772 -23611 +23618 @@ -17121,17 +17194,17 @@ 1 2 -1758460 +1758162 2 4 -154469 +154464 4 3608 -94776 +94737 @@ -17147,42 +17220,42 @@ 1 2 -52158 +52083 2 3 -19236 +19276 3 4 -10890 +10910 4 5 -7687 +7686 5 8 -10517 +10515 8 15 -9508 +9506 15 47 -9530 +9528 47 165630 -6777 +6776 @@ -17198,37 +17271,37 @@ 1 2 -54977 +54901 2 3 -18786 +18826 3 4 -11789 +11809 4 6 -11197 +11195 6 11 -10736 +10734 11 27 -9486 +9484 27 164602 -9332 +9331 @@ -17244,32 +17317,32 @@ 1 2 -76307 +76283 2 3 -16889 +16897 3 4 -8861 +8859 4 7 -10473 +10471 7 27 -9519 +9517 27 125807 -4255 +4254 @@ -17285,32 +17358,32 @@ 1 2 -72820 +72807 2 3 -19027 +19024 3 4 -6974 +6973 4 7 -11186 +11184 7 21 -9749 +9747 21 10073 -6547 +6546 @@ -17326,22 +17399,22 @@ 1 2 -892478 +892233 2 3 -149062 +149124 3 6 -113420 +113389 6 128450 -77448 +77445 @@ -17357,22 +17430,22 @@ 1 2 -941237 +940983 2 3 -114483 +114551 3 6 -102661 +102632 6 128224 -74026 +74024 @@ -17388,17 +17461,17 @@ 1 2 -1055370 +1055162 2 3 -85092 +85099 3 118388 -91946 +91930 @@ -17414,12 +17487,12 @@ 1 2 -1223438 +1223223 2 52 -8970 +8969 @@ -17429,11 +17502,11 @@ var_def -2437456 +2437137 id -2437456 +2437137 @@ -17503,19 +17576,19 @@ type_decls -1332120 +1331886 id -1332120 +1331886 type_id -1300371 +1300142 location -1086812 +1086621 @@ -17529,7 +17602,7 @@ 1 2 -1332120 +1331886 @@ -17545,7 +17618,7 @@ 1 2 -1332120 +1331886 @@ -17561,12 +17634,12 @@ 1 2 -1277275 +1277050 2 24 -23096 +23092 @@ -17582,12 +17655,12 @@ 1 2 -1278569 +1278344 2 24 -21802 +21798 @@ -17603,12 +17676,12 @@ 1 2 -1031352 +1031171 2 506 -55459 +55450 @@ -17624,12 +17697,12 @@ 1 2 -1032833 +1032651 2 506 -53979 +53969 @@ -17639,45 +17712,45 @@ type_def -937716 +937551 id -937716 +937551 type_decl_top -268689 +268642 type_decl -268689 +268642 namespace_decls -136867 +136843 id -136867 +136843 namespace_id -7676 +7675 location -122248 +122226 bodylocation -122577 +122555 @@ -17691,7 +17764,7 @@ 1 2 -136867 +136843 @@ -17707,7 +17780,7 @@ 1 2 -136867 +136843 @@ -17723,7 +17796,7 @@ 1 2 -136867 +136843 @@ -17739,7 +17812,7 @@ 1 2 -3619 +3618 2 @@ -17754,7 +17827,7 @@ 4 7 -647 +646 7 @@ -17790,7 +17863,7 @@ 1 2 -3619 +3618 2 @@ -17805,7 +17878,7 @@ 4 7 -647 +646 7 @@ -17841,7 +17914,7 @@ 1 2 -3619 +3618 2 @@ -17856,7 +17929,7 @@ 4 7 -647 +646 7 @@ -17892,12 +17965,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17913,12 +17986,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17934,7 +18007,7 @@ 1 2 -121502 +121481 2 @@ -17955,12 +18028,12 @@ 1 2 -114560 +114540 2 11 -8016 +8015 @@ -17976,12 +18049,12 @@ 1 2 -114560 +114540 2 9 -8016 +8015 @@ -17997,7 +18070,7 @@ 1 2 -122182 +122161 2 @@ -18012,19 +18085,19 @@ usings -291435 +291384 id -291435 +291384 element_id -46401 +46392 location -23864 +23859 @@ -18038,7 +18111,7 @@ 1 2 -291435 +291384 @@ -18054,7 +18127,7 @@ 1 2 -291435 +291384 @@ -18070,7 +18143,7 @@ 1 2 -39393 +39386 2 @@ -18080,7 +18153,7 @@ 4 127 -3257 +3256 @@ -18096,7 +18169,7 @@ 1 2 -39393 +39386 2 @@ -18106,7 +18179,7 @@ 4 127 -3257 +3256 @@ -18122,12 +18195,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18153,12 +18226,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18178,15 +18251,15 @@ using_container -458088 +458008 parent -11230 +11228 child -291435 +291384 @@ -18200,12 +18273,12 @@ 1 2 -3213 +3212 2 4 -943 +942 4 @@ -18230,7 +18303,7 @@ 178 179 -1261 +1260 179 @@ -18256,17 +18329,17 @@ 1 2 -215851 +215813 2 3 -50371 +50362 3 11 -23140 +23136 13 @@ -18647,15 +18720,15 @@ params -4644903 +4644085 id -4627839 +4627024 function -3043840 +3043304 index @@ -18663,7 +18736,7 @@ type_id -1856790 +1856463 @@ -18677,7 +18750,7 @@ 1 2 -4627170 +4626355 2 @@ -18698,7 +18771,7 @@ 1 2 -4627839 +4627024 @@ -18714,12 +18787,12 @@ 1 2 -4612792 +4611980 2 4 -15046 +15043 @@ -18735,22 +18808,22 @@ 1 2 -2166606 +2166224 2 3 -475109 +475026 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18766,22 +18839,22 @@ 1 2 -2166606 +2166224 2 3 -475109 +475026 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18797,22 +18870,22 @@ 1 2 -2283184 +2282782 2 3 -470964 +470881 3 5 -254323 +254278 5 20 -35368 +35362 @@ -18951,22 +19024,22 @@ 1 2 -1504718 +1504453 2 3 -186712 +186679 3 14 -139488 +139463 14 5175 -25871 +25866 @@ -18982,22 +19055,22 @@ 1 2 -1524579 +1524311 2 3 -179846 +179815 3 23 -139718 +139694 23 4690 -12644 +12642 @@ -19013,12 +19086,12 @@ 1 2 -1745102 +1744795 2 65 -111687 +111667 @@ -19116,19 +19189,19 @@ membervariables -310298 +310243 id -305681 +305627 type_id -132919 +132895 name -53222 +53213 @@ -19142,12 +19215,12 @@ 1 2 -301217 +301164 2 7 -4463 +4462 @@ -19163,7 +19236,7 @@ 1 2 -305681 +305627 @@ -19179,22 +19252,22 @@ 1 2 -108068 +108049 2 3 -12272 +12269 3 9 -10056 +10054 9 1712 -2522 +2521 @@ -19210,17 +19283,17 @@ 1 2 -115119 +115099 2 3 -9091 +9089 3 266 -8707 +8706 @@ -19236,17 +19309,17 @@ 1 2 -28097 +28092 2 3 -8170 +8168 3 4 -5373 +5372 4 @@ -19256,12 +19329,12 @@ 6 15 -4090 +4089 15 1967 -3476 +3475 @@ -19277,12 +19350,12 @@ 1 2 -34293 +34287 2 3 -6854 +6853 3 @@ -19292,7 +19365,7 @@ 4 7 -4299 +4298 7 @@ -20844,19 +20917,19 @@ builtintypes -504 +515 id -504 +515 name -504 +515 kind -504 +515 size @@ -20882,7 +20955,7 @@ 1 2 -504 +515 @@ -20898,7 +20971,7 @@ 1 2 -504 +515 @@ -20914,7 +20987,7 @@ 1 2 -504 +515 @@ -20930,7 +21003,7 @@ 1 2 -504 +515 @@ -20946,7 +21019,7 @@ 1 2 -504 +515 @@ -20962,7 +21035,7 @@ 1 2 -504 +515 @@ -20978,7 +21051,7 @@ 1 2 -504 +515 @@ -20994,7 +21067,7 @@ 1 2 -504 +515 @@ -21010,7 +21083,7 @@ 1 2 -504 +515 @@ -21026,7 +21099,7 @@ 1 2 -504 +515 @@ -21042,7 +21115,7 @@ 1 2 -504 +515 @@ -21058,7 +21131,7 @@ 1 2 -504 +515 @@ -21074,7 +21147,7 @@ 1 2 -504 +515 @@ -21090,7 +21163,7 @@ 1 2 -504 +515 @@ -21106,7 +21179,7 @@ 1 2 -504 +515 @@ -21135,8 +21208,8 @@ 10 -6 -7 +7 +8 10 @@ -21181,8 +21254,8 @@ 10 -6 -7 +7 +8 10 @@ -21227,8 +21300,8 @@ 10 -6 -7 +7 +8 10 @@ -21310,8 +21383,8 @@ 10 -28 -29 +29 +30 10 @@ -21336,8 +21409,8 @@ 10 -28 -29 +29 +30 10 @@ -21362,8 +21435,8 @@ 10 -28 -29 +29 +30 10 @@ -21420,8 +21493,8 @@ 10 -7 -8 +8 +9 10 @@ -21456,8 +21529,8 @@ 10 -7 -8 +8 +9 10 @@ -21492,8 +21565,8 @@ 10 -7 -8 +8 +9 10 @@ -21556,15 +21629,15 @@ derivedtypes -4417712 +4630204 id -4417712 +4630204 name -2172605 +2324208 kind @@ -21572,7 +21645,7 @@ type_id -2606150 +2775550 @@ -21586,7 +21659,7 @@ 1 2 -4417712 +4630204 @@ -21602,7 +21675,7 @@ 1 2 -4417712 +4630204 @@ -21618,7 +21691,7 @@ 1 2 -4417712 +4630204 @@ -21634,17 +21707,17 @@ 1 2 -1570509 +1682503 2 3 -487524 +523359 3 45177 -114571 +118345 @@ -21660,7 +21733,7 @@ 1 2 -2172572 +2324175 2 @@ -21681,17 +21754,17 @@ 1 2 -1570750 +1682744 2 3 -487293 +523129 3 45159 -114560 +118334 @@ -21720,8 +21793,8 @@ 10 -27116 -27117 +31133 +31134 10 @@ -21735,8 +21808,8 @@ 10 -96890 -96891 +112323 +112324 10 @@ -21776,8 +21849,8 @@ 10 -14760 -14761 +17432 +17433 10 @@ -21786,8 +21859,8 @@ 10 -48258 -48259 +59447 +59448 10 @@ -21822,8 +21895,8 @@ 10 -27116 -27117 +31133 +31134 10 @@ -21837,8 +21910,8 @@ 10 -96559 -96560 +111992 +111993 10 @@ -21860,22 +21933,22 @@ 1 2 -1546239 +1704948 2 3 -372700 +369630 3 4 -633867 +628985 4 202 -53343 +71985 @@ -21891,22 +21964,22 @@ 1 2 -1547456 +1706165 2 3 -372546 +369476 3 4 -632803 +627922 4 198 -53343 +71985 @@ -21922,22 +21995,22 @@ 1 2 -1547774 +1706483 2 3 -373829 +370759 3 4 -632759 +627878 4 7 -51785 +70428 @@ -21947,11 +22020,11 @@ pointerishsize -3331733 +3375193 id -3331733 +3375193 size @@ -21973,7 +22046,7 @@ 1 2 -3331733 +3375193 @@ -21989,7 +22062,7 @@ 1 2 -3331733 +3375193 @@ -22008,8 +22081,8 @@ 10 -303777 -303778 +307794 +307795 10 @@ -22040,8 +22113,8 @@ 12 -303798 -303799 +307815 +307816 10 @@ -22068,11 +22141,11 @@ arraysizes -17196 +17193 id -17196 +17193 num_elements @@ -22080,7 +22153,7 @@ bytesize -2511 +2510 alignment @@ -22098,7 +22171,7 @@ 1 2 -17196 +17193 @@ -22114,7 +22187,7 @@ 1 2 -17196 +17193 @@ -22130,7 +22203,7 @@ 1 2 -17196 +17193 @@ -22151,7 +22224,7 @@ 2 3 -1272 +1271 3 @@ -22192,7 +22265,7 @@ 1 2 -1590 +1589 2 @@ -22228,7 +22301,7 @@ 1 2 -1590 +1589 2 @@ -22315,7 +22388,7 @@ 1 2 -1908 +1907 2 @@ -22346,7 +22419,7 @@ 1 2 -1952 +1951 2 @@ -22504,15 +22577,15 @@ typedefbase -1819645 +1819324 id -1819645 +1819324 type_id -847360 +847211 @@ -22526,7 +22599,7 @@ 1 2 -1819645 +1819324 @@ -22542,22 +22615,22 @@ 1 2 -656634 +656518 2 3 -87910 +87895 3 6 -69596 +69583 6 5503 -33218 +33213 @@ -22567,19 +22640,19 @@ decltypes -47004 +46996 id -47004 +46996 expr -43440 +43432 base_type -8630 +8629 parentheses_would_change_meaning @@ -22597,7 +22670,7 @@ 1 2 -47004 +46996 @@ -22613,7 +22686,7 @@ 1 2 -47004 +46996 @@ -22629,7 +22702,7 @@ 1 2 -47004 +46996 @@ -22645,12 +22718,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22666,12 +22739,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22687,7 +22760,7 @@ 1 2 -43440 +43432 @@ -22703,12 +22776,12 @@ 1 2 -5823 +5822 2 3 -2522 +2521 3 @@ -22729,12 +22802,12 @@ 1 2 -2314 +2313 2 3 -5702 +5701 3 @@ -22755,7 +22828,7 @@ 1 2 -8630 +8629 @@ -22828,15 +22901,15 @@ usertypes -4193822 +4193084 id -4193822 +4193084 name -879383 +879229 kind @@ -22854,7 +22927,7 @@ 1 2 -4193822 +4193084 @@ -22870,7 +22943,7 @@ 1 2 -4193822 +4193084 @@ -22886,22 +22959,22 @@ 1 2 -577453 +577351 2 3 -194794 +194760 3 7 -69311 +69298 7 32744 -37824 +37818 @@ -22917,12 +22990,12 @@ 1 2 -826742 +826596 2 10 -52641 +52632 @@ -23059,11 +23132,11 @@ usertypesize -1386571 +1386327 id -1386571 +1386327 size @@ -23085,7 +23158,7 @@ 1 2 -1386571 +1386327 @@ -23101,7 +23174,7 @@ 1 2 -1386571 +1386327 @@ -23354,15 +23427,15 @@ mangled_name -4190543 +4189805 id -4190543 +4189805 mangled_name -483674 +483589 @@ -23376,7 +23449,7 @@ 1 2 -4190543 +4189805 @@ -23392,32 +23465,32 @@ 1 2 -292082 +292031 2 3 -62292 +62281 3 4 -33339 +33333 4 7 -36969 +36963 7 24 -37068 +37061 24 8580 -21922 +21919 @@ -23427,59 +23500,59 @@ is_pod_class -589209 +589105 id -589209 +589105 is_standard_layout_class -1159183 +1158979 id -1159183 +1158979 is_complete -1365065 +1364825 id -1365065 +1364825 is_class_template -225348 +225308 id -225348 +225308 class_instantiation -1157790 +1157586 to -1156222 +1156018 from -68027 +68015 @@ -23493,7 +23566,7 @@ 1 2 -1154741 +1154538 2 @@ -23514,47 +23587,47 @@ 1 2 -19959 +19956 2 3 -11997 +11995 3 4 -6854 +6853 4 5 -4617 +4616 5 7 -5637 +5636 7 11 -6053 +6052 11 20 -5198 +5197 20 84 -5110 +5109 84 4845 -2599 +2598 @@ -23564,11 +23637,11 @@ class_template_argument -3035999 +3035464 type_id -1392811 +1392566 index @@ -23576,7 +23649,7 @@ arg_type -860904 +860752 @@ -23590,27 +23663,27 @@ 1 2 -567111 +567011 2 3 -433731 +433655 3 4 -244979 +244936 4 7 -122807 +122786 7 113 -24182 +24177 @@ -23626,22 +23699,22 @@ 1 2 -593344 +593239 2 3 -445959 +445881 3 4 -258435 +258390 4 113 -95072 +95055 @@ -23749,27 +23822,27 @@ 1 2 -522278 +522186 2 3 -187435 +187402 3 4 -56710 +56700 4 11 -67391 +67379 11 11852 -27088 +27083 @@ -23785,17 +23858,17 @@ 1 2 -746453 +746322 2 3 -95543 +95527 3 22 -18906 +18903 @@ -23805,11 +23878,11 @@ class_template_argument_value -345798 +345737 type_id -223846 +223806 index @@ -23817,7 +23890,7 @@ arg_value -328240 +328182 @@ -23831,17 +23904,17 @@ 1 2 -201484 +201449 2 3 -13708 +13706 3 14 -8652 +8651 @@ -23857,17 +23930,17 @@ 1 2 -189859 +189826 2 3 -16921 +16919 3 37 -16790 +16787 44 @@ -24010,12 +24083,12 @@ 1 2 -311000 +310945 2 4 -17240 +17236 @@ -24031,7 +24104,7 @@ 1 2 -328240 +328182 @@ -24041,15 +24114,15 @@ is_proxy_class_for -46379 +46371 id -46379 +46371 templ_param_id -46379 +46371 @@ -24063,7 +24136,7 @@ 1 2 -46379 +46371 @@ -24079,7 +24152,7 @@ 1 2 -46379 +46371 @@ -24395,26 +24468,26 @@ is_function_template -983756 +983582 id -983756 +983582 function_instantiation -708310 +708185 to -708310 +708185 from -129333 +129310 @@ -24428,7 +24501,7 @@ 1 2 -708310 +708185 @@ -24444,37 +24517,37 @@ 1 2 -61009 +60998 2 3 -30839 +30833 3 4 -7347 +7346 4 5 -8817 +8815 5 10 -10001 +10000 10 71 -9705 +9704 71 653 -1612 +1611 @@ -24484,11 +24557,11 @@ function_template_argument -1910528 +1910191 function_id -1054361 +1054175 index @@ -24496,7 +24569,7 @@ arg_type -338450 +338391 @@ -24510,22 +24583,22 @@ 1 2 -583583 +583480 2 3 -291007 +290956 3 4 -127764 +127742 4 21 -52005 +51996 @@ -24541,22 +24614,22 @@ 1 2 -598005 +597899 2 3 -288693 +288642 3 4 -110941 +110922 4 21 -56720 +56711 @@ -24794,27 +24867,27 @@ 1 2 -226127 +226087 2 3 -45117 +45110 3 6 -27669 +27664 6 19 -25607 +25603 19 2030 -13928 +13925 @@ -24830,12 +24903,12 @@ 1 2 -314827 +314772 2 12 -23622 +23618 @@ -24845,11 +24918,11 @@ function_template_argument_value -198062 +198028 function_id -107081 +107062 index @@ -24857,7 +24930,7 @@ arg_value -170601 +170571 @@ -24871,12 +24944,12 @@ 1 2 -101564 +101546 2 14 -5516 +5515 @@ -24892,17 +24965,17 @@ 1 2 -84960 +84945 2 3 -16176 +16173 3 113 -5944 +5943 @@ -25030,12 +25103,12 @@ 1 2 -143644 +143619 2 3 -26452 +26447 3 @@ -25056,7 +25129,7 @@ 1 2 -170601 +170571 @@ -25066,26 +25139,26 @@ is_variable_template -17810 +17807 id -17810 +17807 variable_instantiation -35807 +35800 to -35807 +35800 from -6470 +6469 @@ -25099,7 +25172,7 @@ 1 2 -35807 +35800 @@ -25115,12 +25188,12 @@ 1 2 -2237 +2236 2 3 -1908 +1907 3 @@ -25507,15 +25580,15 @@ routinetypes -430474 +430398 id -430474 +430398 return_type -177565 +177534 @@ -25529,7 +25602,7 @@ 1 2 -430474 +430398 @@ -25545,17 +25618,17 @@ 1 2 -143107 +143082 2 3 -18128 +18125 3 9 -13324 +13322 9 @@ -25570,11 +25643,11 @@ routinetypeargs -719836 +719710 routine -351841 +351779 index @@ -25582,7 +25655,7 @@ type_id -205564 +205528 @@ -25596,27 +25669,27 @@ 1 2 -161926 +161898 2 3 -95949 +95932 3 4 -53935 +53925 4 6 -32330 +32324 6 33 -7698 +7697 @@ -25632,22 +25705,22 @@ 1 2 -186745 +186712 2 3 -96706 +96689 3 4 -47662 +47653 4 22 -20727 +20723 @@ -25805,27 +25878,27 @@ 1 2 -122412 +122391 2 3 -40840 +40833 3 4 -13215 +13212 4 7 -16636 +16633 7 1349 -12458 +12456 @@ -25841,17 +25914,17 @@ 1 2 -154107 +154080 2 3 -39437 +39430 3 33 -12019 +12017 @@ -25861,19 +25934,19 @@ ptrtomembers -12633 +12631 id -12633 +12631 type_id -9398 +9397 class_id -6360 +6359 @@ -25887,7 +25960,7 @@ 1 2 -12633 +12631 @@ -25903,7 +25976,7 @@ 1 2 -12633 +12631 @@ -25919,7 +25992,7 @@ 1 2 -9036 +9035 2 @@ -25940,7 +26013,7 @@ 1 2 -9036 +9035 2 @@ -25961,7 +26034,7 @@ 1 2 -5340 +5339 2 @@ -25987,7 +26060,7 @@ 1 2 -5340 +5339 2 @@ -26007,15 +26080,15 @@ specifiers -493 +504 id -493 +504 str -493 +504 @@ -26029,7 +26102,7 @@ 1 2 -493 +504 @@ -26045,7 +26118,7 @@ 1 2 -493 +504 @@ -26055,11 +26128,11 @@ typespecifiers -1331934 +1500944 type_id -1325069 +1494058 spec_id @@ -26077,12 +26150,12 @@ 1 2 -1318203 +1487172 2 3 -6865 +6886 @@ -26111,8 +26184,8 @@ 10 -955 -956 +957 +958 10 @@ -26126,8 +26199,8 @@ 10 -96425 -96426 +111858 +111859 10 @@ -26138,11 +26211,11 @@ funspecifiers -11102993 +11101038 func_id -3417758 +3417156 spec_id @@ -26160,27 +26233,27 @@ 1 2 -342311 +342250 2 3 -436988 +436911 3 4 -842710 +842562 4 5 -1677316 +1677020 5 8 -118431 +118411 @@ -26384,11 +26457,11 @@ attributes -413159 +413730 id -413159 +413730 kind @@ -26404,7 +26477,7 @@ location -89984 +90510 @@ -26418,7 +26491,7 @@ 1 2 -413159 +413730 @@ -26434,7 +26507,7 @@ 1 2 -413159 +413730 @@ -26450,7 +26523,7 @@ 1 2 -413159 +413730 @@ -26466,7 +26539,7 @@ 1 2 -413159 +413730 @@ -26480,8 +26553,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26528,8 +26601,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26579,12 +26652,12 @@ 4 -645 +648 780 4 -806 +807 1148 4 @@ -26594,7 +26667,7 @@ 4 -25877 +26224 35247 4 @@ -26678,11 +26751,11 @@ 440 -627 +628 4 -642 +645 776 4 @@ -26718,8 +26791,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26766,8 +26839,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26784,12 +26857,12 @@ 1 2 -26208 +26730 2 3 -5310 +5313 3 @@ -26798,13 +26871,8 @@ 4 -7 -6755 - - -7 8 -631 +7387 8 @@ -26830,7 +26898,7 @@ 1 2 -89984 +90510 @@ -26846,7 +26914,7 @@ 1 2 -27889 +28415 2 @@ -26882,7 +26950,7 @@ 1 2 -89984 +90510 @@ -26892,11 +26960,11 @@ attribute_args -152050 +152615 id -152050 +152615 kind @@ -26904,7 +26972,7 @@ attribute -150751 +151316 index @@ -26912,7 +26980,7 @@ location -56842 +57362 @@ -26926,7 +26994,7 @@ 1 2 -152050 +152615 @@ -26942,7 +27010,7 @@ 1 2 -152050 +152615 @@ -26958,7 +27026,7 @@ 1 2 -152050 +152615 @@ -26974,7 +27042,7 @@ 1 2 -152050 +152615 @@ -26993,8 +27061,8 @@ 1 -89512 -89513 +89859 +89860 1 @@ -27014,8 +27082,8 @@ 1 -89030 -89031 +89377 +89378 1 @@ -27056,8 +27124,8 @@ 1 -34672 -34673 +34991 +34992 1 @@ -27074,7 +27142,7 @@ 1 2 -149973 +150538 2 @@ -27095,7 +27163,7 @@ 1 2 -150261 +150826 2 @@ -27116,7 +27184,7 @@ 1 2 -149973 +150538 2 @@ -27137,7 +27205,7 @@ 1 2 -149978 +150543 2 @@ -27171,8 +27239,8 @@ 1 -92593 -92594 +92940 +92941 1 @@ -27223,8 +27291,8 @@ 1 -92608 -92609 +92955 +92956 1 @@ -27254,8 +27322,8 @@ 1 -34262 -34263 +34581 +34582 1 @@ -27272,17 +27340,17 @@ 1 2 -26779 +27295 2 3 -8446 +8429 3 5 -2865 +2886 5 @@ -27308,7 +27376,7 @@ 1 2 -51047 +51567 2 @@ -27329,17 +27397,17 @@ 1 2 -26765 +27281 2 3 -8463 +8445 3 5 -2863 +2884 5 @@ -27365,7 +27433,7 @@ 1 2 -56837 +57357 3 @@ -27380,11 +27448,11 @@ attribute_arg_value -152026 +152591 arg -152026 +152591 value @@ -27402,7 +27470,7 @@ 1 2 -152026 +152591 @@ -27432,7 +27500,7 @@ 10 -23973 +23976 133 @@ -27549,15 +27617,15 @@ typeattributes -19323 +19320 type_id -17941 +17938 spec_id -19323 +19320 @@ -27571,7 +27639,7 @@ 1 2 -17240 +17236 2 @@ -27592,7 +27660,7 @@ 1 2 -19323 +19320 @@ -27602,15 +27670,15 @@ funcattributes -304387 +304333 func_id -164240 +164211 spec_id -304387 +304333 @@ -27624,17 +27692,17 @@ 1 2 -89687 +89671 2 3 -12579 +12576 3 4 -59967 +59956 4 @@ -27655,7 +27723,7 @@ 1 2 -304387 +304333 @@ -27665,15 +27733,15 @@ varattributes -371203 +371224 var_id -322400 +322421 spec_id -371203 +371224 @@ -27687,7 +27755,7 @@ 1 2 -273633 +273654 2 @@ -27713,7 +27781,7 @@ 1 2 -371203 +371224 @@ -27771,15 +27839,15 @@ unspecifiedtype -9070084 +9281768 type_id -9070084 +9281768 unspecified_type_id -4976818 +5011819 @@ -27793,7 +27861,7 @@ 1 2 -9070084 +9281768 @@ -27809,17 +27877,22 @@ 1 2 -2709392 +2685220 2 3 -1952849 +1947648 3 +42 +375957 + + +42 7950 -314575 +2993 @@ -27829,11 +27902,11 @@ member -4921643 +4920776 parent -814481 +814338 index @@ -27841,7 +27914,7 @@ child -4906081 +4905217 @@ -27855,47 +27928,47 @@ 1 2 -42321 +42313 2 3 -223780 +223740 3 4 -204621 +204585 4 5 -86923 +86908 5 7 -65900 +65888 7 9 -61612 +61601 9 15 -62050 +62040 15 47 -61184 +61173 47 245 -6086 +6085 @@ -27911,47 +27984,47 @@ 1 2 -41663 +41656 2 3 -223604 +223565 3 4 -199378 +199343 4 5 -89731 +89715 5 7 -66371 +66360 7 9 -61689 +61678 9 15 -62972 +62961 15 42 -61272 +61261 42 281 -7797 +7796 @@ -28109,7 +28182,7 @@ 1 2 -4906081 +4905217 @@ -28125,12 +28198,12 @@ 1 2 -4890727 +4889866 2 7 -15353 +15351 @@ -28140,15 +28213,15 @@ enclosingfunction -125077 +125055 child -125077 +125055 parent -71405 +71393 @@ -28162,7 +28235,7 @@ 1 2 -125077 +125055 @@ -28178,22 +28251,22 @@ 1 2 -38340 +38333 2 3 -21078 +21074 3 4 -6536 +6535 4 7 -5373 +5372 7 @@ -28208,15 +28281,15 @@ derivations -390258 +390189 derivation -390258 +390189 sub -364442 +364378 index @@ -28224,11 +28297,11 @@ super -235701 +235659 location -86978 +86963 @@ -28242,7 +28315,7 @@ 1 2 -390258 +390189 @@ -28258,7 +28331,7 @@ 1 2 -390258 +390189 @@ -28274,7 +28347,7 @@ 1 2 -390258 +390189 @@ -28290,7 +28363,7 @@ 1 2 -390258 +390189 @@ -28306,12 +28379,12 @@ 1 2 -341872 +341812 2 7 -22569 +22565 @@ -28327,12 +28400,12 @@ 1 2 -351490 +351428 2 7 -12951 +12949 @@ -28348,12 +28421,12 @@ 1 2 -341883 +341823 2 7 -22558 +22555 @@ -28369,12 +28442,12 @@ 1 2 -351479 +351417 2 7 -12962 +12960 @@ -28554,12 +28627,12 @@ 1 2 -220917 +220879 2 1142 -14783 +14780 @@ -28575,12 +28648,12 @@ 1 2 -220928 +220890 2 1142 -14772 +14769 @@ -28596,7 +28669,7 @@ 1 2 -235251 +235210 2 @@ -28617,12 +28690,12 @@ 1 2 -228342 +228302 2 439 -7358 +7357 @@ -28638,22 +28711,22 @@ 1 2 -66349 +66338 2 3 -8389 +8388 3 7 -6613 +6611 7 795 -5626 +5625 @@ -28669,17 +28742,17 @@ 1 2 -68587 +68575 2 3 -6371 +6370 3 8 -7040 +7039 8 @@ -28700,7 +28773,7 @@ 1 2 -86956 +86941 2 @@ -28721,22 +28794,22 @@ 1 2 -69289 +69276 2 3 -8203 +8201 3 9 -6525 +6524 9 795 -2961 +2960 @@ -28746,11 +28819,11 @@ derspecifiers -392638 +392569 der_id -390225 +390156 spec_id @@ -28768,7 +28841,7 @@ 1 2 -387812 +387744 2 @@ -28814,11 +28887,11 @@ direct_base_offsets -310550 +310496 der_id -310550 +310496 offset @@ -28836,7 +28909,7 @@ 1 2 -310550 +310496 @@ -28922,11 +28995,11 @@ virtual_base_offsets -6338 +6337 sub -3509 +3508 super @@ -28979,7 +29052,7 @@ 1 2 -2961 +2960 2 @@ -29213,23 +29286,23 @@ frienddecls -240340 +240298 id -240340 +240298 type_id -27285 +27280 decl_id -49044 +49035 location -7303 +7302 @@ -29243,7 +29316,7 @@ 1 2 -240340 +240298 @@ -29259,7 +29332,7 @@ 1 2 -240340 +240298 @@ -29275,7 +29348,7 @@ 1 2 -240340 +240298 @@ -29291,17 +29364,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29311,7 +29384,7 @@ 6 8 -2314 +2313 8 @@ -29342,17 +29415,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29362,7 +29435,7 @@ 6 8 -2314 +2313 8 @@ -29393,12 +29466,12 @@ 1 2 -25706 +25701 2 31 -1579 +1578 @@ -29414,7 +29487,7 @@ 1 2 -33690 +33684 2 @@ -29429,12 +29502,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29450,7 +29523,7 @@ 1 2 -33690 +33684 2 @@ -29465,12 +29538,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29486,7 +29559,7 @@ 1 2 -48506 +48498 2 @@ -29507,12 +29580,12 @@ 1 2 -6240 +6239 2 3 -943 +942 3 @@ -29533,7 +29606,7 @@ 1 2 -6865 +6864 2 @@ -29554,7 +29627,7 @@ 1 2 -6251 +6250 2 @@ -29574,19 +29647,19 @@ comments -1580291 +1580013 id -1580291 +1580013 contents -784157 +784019 location -1580291 +1580013 @@ -29600,7 +29673,7 @@ 1 2 -1580291 +1580013 @@ -29616,7 +29689,7 @@ 1 2 -1580291 +1580013 @@ -29632,17 +29705,17 @@ 1 2 -663938 +663821 2 3 -75101 +75088 3 10738 -45117 +45110 @@ -29658,17 +29731,17 @@ 1 2 -663938 +663821 2 3 -75101 +75088 3 10738 -45117 +45110 @@ -29684,7 +29757,7 @@ 1 2 -1580291 +1580013 @@ -29700,7 +29773,7 @@ 1 2 -1580291 +1580013 @@ -29710,15 +29783,15 @@ commentbinding -713289 +713207 id -618370 +618261 element -684512 +684435 @@ -29732,17 +29805,17 @@ 1 2 -557010 +556868 2 3 -49044 +49079 3 97 -12315 +12313 @@ -29758,12 +29831,12 @@ 1 2 -655735 +655663 2 3 -28777 +28772 @@ -29826,22 +29899,22 @@ compgenerated -6707729 +6707974 id -6707729 +6707974 synthetic_destructor_call -59594 +59605 element -46379 +46392 i @@ -29849,7 +29922,7 @@ destructor_call -49449 +49463 @@ -29863,12 +29936,12 @@ 1 2 -36936 +36952 2 3 -6766 +6765 3 @@ -29889,12 +29962,12 @@ 1 2 -36936 +36952 2 3 -6766 +6765 3 @@ -29933,8 +30006,8 @@ 21 -4229 -4230 +4231 +4232 10 @@ -29969,8 +30042,8 @@ 21 -3563 -3564 +3565 +3566 10 @@ -29987,17 +30060,17 @@ 1 2 -43604 +43618 2 3 -3619 +3618 3 26 -2226 +2225 @@ -30013,7 +30086,7 @@ 1 2 -49449 +49463 @@ -30023,15 +30096,15 @@ namespaces -7687 +7686 id -7687 +7686 name -4134 +4133 @@ -30045,7 +30118,7 @@ 1 2 -7687 +7686 @@ -30061,7 +30134,7 @@ 1 2 -3476 +3475 2 @@ -30092,15 +30165,15 @@ namespacembrs -1603322 +1603040 parentid -7161 +7160 memberid -1603322 +1603040 @@ -30174,7 +30247,7 @@ 778 39485 -318 +317 @@ -30190,7 +30263,7 @@ 1 2 -1603322 +1603040 @@ -30490,11 +30563,11 @@ iscall -2320176 +2320337 caller -2320176 +2320337 kind @@ -30512,7 +30585,7 @@ 1 2 -2320176 +2320337 @@ -30531,13 +30604,13 @@ 10 -6428 -6429 +6429 +6430 10 -203747 -203748 +203798 +203799 10 @@ -30548,11 +30621,11 @@ numtemplatearguments -164712 +164694 expr_id -164712 +164694 num @@ -30570,7 +30643,7 @@ 1 2 -164712 +164694 @@ -30599,8 +30672,8 @@ 10 -14306 -14307 +14307 +14308 10 @@ -31146,11 +31219,11 @@ expr_allocator -30334 +30329 expr -30334 +30329 func @@ -31172,7 +31245,7 @@ 1 2 -30334 +30329 @@ -31188,7 +31261,7 @@ 1 2 -30334 +30329 @@ -31297,11 +31370,11 @@ expr_deallocator -33306 +33300 expr -33306 +33300 func @@ -31323,7 +31396,7 @@ 1 2 -33306 +33300 @@ -31339,7 +31412,7 @@ 1 2 -33306 +33300 @@ -32525,15 +32598,15 @@ expr_ancestor -66075 +66086 exp -65373 +65384 ancestor -47092 +47105 @@ -32547,12 +32620,12 @@ 1 2 -64737 +64748 2 4 -636 +635 @@ -32568,12 +32641,12 @@ 1 2 -34929 +34945 2 3 -9705 +9704 3 @@ -32596,11 +32669,11 @@ kind -1096 +598 location -3623125 +5472246 @@ -32644,69 +32717,69 @@ 12 -2 -14 -87 +1 +8 +52 -15 -50 -87 +8 +18 +52 -50 -90 -87 +21 +62 +45 -90 -223 -87 +100 +150 +45 -306 -471 -87 +213 +506 +45 -484 -715 -87 +531 +815 +45 -866 -2036 -87 +835 +2006 +45 -2167 -2960 -87 +2338 +3023 +45 -3202 -4443 -87 +3116 +5545 +45 -4718 -6425 -87 +5585 +10841 +45 -6722 -13441 -87 +13459 +19466 +45 -17876 -114329 -87 +20677 +67545 +45 -192875 -428313 -43 +150195 +817400 +39 @@ -32722,67 +32795,72 @@ 1 4 -98 +45 4 -14 -98 +9 +45 -14 -24 -87 +12 +21 +45 -24 -38 -87 +21 +85 +45 -38 -134 -87 +86 +186 +45 -144 -259 -87 +191 +309 +45 -270 -481 -87 +419 +726 +45 -481 -1076 -87 +740 +1250 +45 -1099 -1408 -87 +1517 +2150 +45 -1427 -2051 -87 +2341 +3752 +45 -2060 -4561 -87 +3790 +7357 +45 -5889 -60114 -87 +7374 +16657 +45 -72726 -118610 -21 +18659 +177292 +45 + + +374826 +374827 +6 @@ -32798,37 +32876,22 @@ 1 2 -1680540 +3700726 2 3 -738546 +1002531 3 -4 -319883 - - -4 5 -276871 +434517 5 -9 -301722 - - -9 -53 -272089 - - -53 -144742 -33471 +306848 +334470 @@ -32844,17 +32907,17 @@ 1 2 -2587089 +4305820 2 3 -806881 +882874 3 -30 -229154 +20 +283551 @@ -32864,15 +32927,15 @@ expr_types -18573253 +18573218 id -18430420 +18430421 typeid -1322513 +1322281 value_category @@ -32890,12 +32953,12 @@ 1 2 -18289045 +18289082 2 4 -141374 +141338 @@ -32911,7 +32974,7 @@ 1 2 -18430420 +18430421 @@ -32927,42 +32990,42 @@ 1 2 -513779 +513809 2 3 -252118 +251899 3 4 -108364 +108356 4 5 -86046 +86097 5 8 -114220 +114156 8 14 -106050 +106009 14 45 -99744 +99715 45 -126302 -42189 +126320 +42237 @@ -32978,17 +33041,17 @@ 1 2 -1170972 +1170755 2 3 -143140 +143126 3 4 -8400 +8399 @@ -33007,13 +33070,13 @@ 10 -370445 -370446 +370542 +370543 10 -1304652 -1304653 +1304851 +1304852 10 @@ -33038,8 +33101,8 @@ 10 -102766 -102767 +102767 +102768 10 @@ -33050,15 +33113,15 @@ new_allocated_type -32133 +32127 expr -32133 +32127 type_id -16516 +16513 @@ -33072,7 +33135,7 @@ 1 2 -32133 +32127 @@ -33088,7 +33151,7 @@ 1 2 -10341 +10340 2 @@ -33713,15 +33776,15 @@ condition_decl_bind -7007 +7028 expr -7007 +7028 decl -7007 +7028 @@ -33735,7 +33798,7 @@ 1 2 -7007 +7028 @@ -33751,7 +33814,7 @@ 1 2 -7007 +7028 @@ -33761,11 +33824,11 @@ typeid_bind -4419 +4418 expr -4419 +4418 type_id @@ -33783,7 +33846,7 @@ 1 2 -4419 +4418 @@ -35478,11 +35541,11 @@ stmts -4688881 +4688625 id -4688881 +4688625 kind @@ -35490,7 +35553,7 @@ location -1194069 +1193858 @@ -35504,7 +35567,7 @@ 1 2 -4688881 +4688625 @@ -35520,7 +35583,7 @@ 1 2 -4688881 +4688625 @@ -35554,8 +35617,8 @@ 10 -735 -736 +736 +737 10 @@ -35569,13 +35632,13 @@ 10 -2235 -2236 +2237 +2238 10 -2266 -2267 +2267 +2268 10 @@ -35584,13 +35647,13 @@ 10 -2826 -2827 +2827 +2828 10 -3119 -3120 +3121 +3122 10 @@ -35599,33 +35662,33 @@ 10 -4772 -4773 +4775 +4776 10 -30477 -30478 +30484 +30485 10 -55902 -55903 +55911 +55912 10 -90767 -90768 +90778 +90779 10 -103054 -103055 +103056 +103057 10 -120826 -120827 +120839 +120840 10 @@ -35748,32 +35811,32 @@ 1 2 -677987 +677440 2 3 -181579 +181953 3 4 -107870 +107851 4 6 -102135 +102117 6 22 -101531 +101535 22 5041 -22964 +22960 @@ -35789,12 +35852,12 @@ 1 2 -1170479 +1170273 2 9 -23589 +23585 @@ -36092,15 +36155,15 @@ while_body -30992 +30998 while_stmt -30992 +30998 body_id -30992 +30998 @@ -36114,7 +36177,7 @@ 1 2 -30992 +30998 @@ -36130,7 +36193,7 @@ 1 2 -30992 +30998 @@ -37427,15 +37490,15 @@ blockscope -1325069 +1324978 block -1325069 +1324978 enclosing -1186907 +1186775 @@ -37449,7 +37512,7 @@ 1 2 -1325069 +1324978 @@ -37465,12 +37528,12 @@ 1 2 -1106552 +1106391 2 509 -80354 +80384 @@ -37666,11 +37729,11 @@ preprocdirects -1323588 +1323355 id -1323588 +1323355 kind @@ -37678,7 +37741,7 @@ location -1317271 +1317039 @@ -37692,7 +37755,7 @@ 1 2 -1323588 +1323355 @@ -37708,7 +37771,7 @@ 1 2 -1323588 +1323355 @@ -37876,12 +37939,12 @@ 1 2 -1316942 +1316710 2 235 -329 +328 @@ -37897,7 +37960,7 @@ 1 2 -1317271 +1317039 @@ -37907,15 +37970,15 @@ preprocpair -378798 +378731 begin -300505 +300452 elseelifend -378798 +378731 @@ -37929,17 +37992,17 @@ 1 2 -238618 +238576 2 3 -54549 +54539 3 53 -7336 +7335 @@ -37955,7 +38018,7 @@ 1 2 -378798 +378731 @@ -37965,41 +38028,41 @@ preproctrue -166565 +166536 branch -166565 +166536 preprocfalse -119122 +119101 branch -119122 +119101 preproctext -965408 +965238 id -965408 +965238 head -463561 +463479 body -175580 +175549 @@ -38013,7 +38076,7 @@ 1 2 -965408 +965238 @@ -38029,7 +38092,7 @@ 1 2 -965408 +965238 @@ -38045,17 +38108,17 @@ 1 2 -345963 +345902 2 3 -78172 +78158 3 19 -34776 +34770 19 @@ -38076,12 +38139,12 @@ 1 2 -441879 +441802 2 38 -21681 +21677 @@ -38097,12 +38160,12 @@ 1 2 -165008 +164979 2 64816 -10572 +10570 @@ -38118,12 +38181,12 @@ 1 2 -166489 +166459 2 21810 -9091 +9089 @@ -38133,15 +38196,15 @@ includes -290843 +290791 id -290843 +290791 included -54604 +54594 @@ -38155,7 +38218,7 @@ 1 2 -290843 +290791 @@ -38171,37 +38234,37 @@ 1 2 -26890 +26886 2 3 -8959 +8958 3 4 -4617 +4616 4 6 -4847 +4846 6 11 -4189 +4188 11 41 -4112 +4111 41 763 -987 +986 @@ -38259,11 +38322,11 @@ link_parent -18153176 +18149980 element -4992577 +4991698 link_target @@ -38281,32 +38344,32 @@ 1 2 -1493422 +1493159 2 3 -1883187 +1882856 3 4 -718838 +718712 4 6 -400863 +400792 6 29 -398143 +398073 29 45 -98121 +98103 diff --git a/cpp/ql/test/examples/expressions/PrintAST.expected b/cpp/ql/test/examples/expressions/PrintAST.expected index 9a782825164..585ebae6ff4 100644 --- a/cpp/ql/test/examples/expressions/PrintAST.expected +++ b/cpp/ql/test/examples/expressions/PrintAST.expected @@ -430,28 +430,28 @@ DynamicCast.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Base * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 4| expr: [ThisExpr] this +# 4| Type = [PointerType] Derived * +# 4| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Base & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Base -#-----| ValueCategory = lvalue +# 4| expr: [PointerDereferenceExpr] * ... +# 4| Type = [SpecifiedType] const Base +# 4| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Base *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Base * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Derived * -#-----| ValueCategory = prvalue +# 4| expr: [AddressOfExpr] & ... +# 4| Type = [PointerType] const Derived * +# 4| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 4| expr: [VariableAccess] p#0 +# 4| Type = [LValueReferenceType] const Derived & +# 4| ValueCategory = prvalue(load) #-----| 1: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Derived & @@ -1248,9 +1248,9 @@ union_etc.cpp: # 6| 0: [PointerFieldAccess] x # 6| Type = [IntType] int # 6| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 6| -1: [ThisExpr] this +# 6| Type = [PointerType] S * +# 6| ValueCategory = prvalue(load) # 6| 1: [VariableAccess] val # 6| Type = [IntType] int # 6| ValueCategory = prvalue(load) @@ -1431,9 +1431,9 @@ union_etc.cpp: # 33| 0: [PointerFieldAccess] q # 33| Type = [IntType] int # 33| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] T * -#-----| ValueCategory = prvalue(load) +# 33| -1: [ThisExpr] this +# 33| Type = [PointerType] T * +# 33| ValueCategory = prvalue(load) # 33| 1: [VariableAccess] val # 33| Type = [IntType] int # 33| ValueCategory = prvalue(load) diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp index 9783a92a762..b1d9b9a45ba 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp @@ -88,3 +88,8 @@ void test2(unsigned int count, bool b) { a = (int*) malloc(sizeof(int) * (1024 - count)); sink(a); // none, as the size expression is too complicated } + +void test3(unsigned int object) { + unsigned int* ptr = &object; + sink(ptr); // TODO, none, but should be (Zero, 1, Zero, 0) +} diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected new file mode 100644 index 00000000000..dc772630430 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected @@ -0,0 +1,12 @@ +| test.cpp:14:18:14:18 | FieldAddress: a | +| test.cpp:15:18:15:18 | FieldAddress: b | +| test.cpp:26:5:26:12 | Store: ... = ... | +| test.cpp:27:13:27:16 | Load: access to array | +| test.cpp:33:5:33:12 | Store: ... = ... | +| test.cpp:48:5:48:16 | Store: ... = ... | +| test.cpp:61:7:61:14 | Store: ... = ... | +| test.cpp:70:7:70:14 | Store: ... = ... | +| test.cpp:81:11:81:14 | Load: access to array | +| test.cpp:85:5:85:12 | Store: ... = ... | +| test.cpp:87:3:87:11 | Store: ... = ... | +| test.cpp:91:3:91:18 | Store: ... = ... | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql new file mode 100644 index 00000000000..7e5c09ed5d1 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql @@ -0,0 +1,6 @@ +import cpp +import experimental.semmle.code.cpp.rangeanalysis.InBoundsPointerDeref + +from PointerDereferenceInstruction ptrAccess +where inBounds(ptrAccess) +select ptrAccess diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp new file mode 100644 index 00000000000..b4368da115c --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp @@ -0,0 +1,126 @@ +void *malloc(unsigned long); + +typedef struct A { + int a; + int b; + char * c; +} A; + +void test1(unsigned int count) { + if (count < 1) { + return; + } + A* ptr = (A*) malloc(sizeof(A) * count); + ptr[count - 1].a = 1000; // in-bounds + ptr[count - 1].b = 1001; // in-bounds + ptr[1].c = 0; // unknown + ptr[count - 2].a = 1002; // dependant on call-site + ptr[count].b = 1003; // out-of-bounds + ptr[-1].c = 0; // out-of-bounds +} + +void test2(unsigned int count) { + int* a = (int*) malloc(sizeof(int) * count); + + for(unsigned int i = 0; i < count; ++i) { + a[i] = 0; // in-bounds + int l = a[i]; // in-bounds + } + + a = (int*) malloc(sizeof(int) * count); + a = a + 2; + for(unsigned int i = 0; i < count - 2; ++i) { + a[i] = 0; // in-bounds + } + + for(unsigned int i = 0; i < count; ++i) { + *a = 1; // in-bounds but not detected, array length tracking is not advanced enough for this + a++; + } + + void* v = malloc(count); + for(unsigned int i = 0; i < count; ++i) { + ((char *)v)[i] = 0; // in-bounds, but due to void-allocation not detected + } + + int stack[100]; + for(unsigned int i = 0; i < 100; ++i) { + stack[i] = 0; // in-bounds + } + + for(unsigned int i = 0; i < count; ++i) { + a = (int*) malloc(sizeof(int) * count); + for (int j = 0; j < count; ++j) { + a[j] = 0; // in-bounds, but not detected due to RangeAnalysis shortcomings + } + } + + for(unsigned int i = 0; i < 10; ++i) { + a = (int*) malloc(sizeof(int) * i); + for (unsigned int j = 0; j < i; ++j) { + a[j] = 0; // in-bounds + } + } + +} +void test3(int count) { + for(int i = 0; i < count; ++i) { + int * a = (int*) malloc(sizeof(int) * i); + for (int j = 0; j < i; ++j) { + a[j] = 0; // in-bounds + } + } +} + + +void test4(unsigned long count) { + if (count < 1) { + return; + } + int* a = (int*) malloc(sizeof(int) * count); + int b = a[0] + 3; // in-bounds + a = a + 2; + unsigned int i = 0; + for(; i < count - 2; ++i) { + a[i] = 0; // in-bounds + } + a[-2] = 0; // in-bounds + a[-3] = 0; // out-of-bounds + a[i] = 0; // out-of-bounds + a[count - 2] = 0; // out-of-bounds + a[count - 3] = 0; // in-bounds +} + +void test5(unsigned int count) { + int* a = (int*) malloc(sizeof(int) * count); + a[0] = 0; // unknown, call-site dependant +} + + +void test6(unsigned int count, bool b) { + if(count < 4) { + return; + } + int* a = (int*) malloc(sizeof(int) * count); + if (b) { + a += 2; + } else { + a += 3; + } // we lose all information about a after the phi-node here + a[-2] = 0; // unknown + a[-3] = 0; // unknown + a[-4] = 0; // unknown + a[0] = 0; // unknown +} + +void test7(unsigned int object) { + unsigned int* ptr = &object; + *ptr = 0; // in-bounds, but needs ArrayLengthAnalysis improvements. +} + +void test8() { + void (*foo)(unsigned int); + foo = &test7; + foo(4); // in-bounds, but needs ArrayLengthAnalysis improvements. +} + diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql similarity index 91% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql index ef158f0de28..1b77763682a 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.RangeAnalysis +import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis import semmle.code.cpp.ir.IR import semmle.code.cpp.controlflow.IRGuards import semmle.code.cpp.ir.ValueNumbering diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql similarity index 86% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql index fbfeb583283..fadd86f8a85 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.SignAnalysis +import experimental.semmle.code.cpp.rangeanalysis.SignAnalysis import semmle.code.cpp.ir.IR string getASignString(Instruction i) { diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp diff --git a/cpp/ql/test/header-variant-tests/deduplication/classes.ql b/cpp/ql/test/header-variant-tests/deduplication/classes.ql index 2fe0098c9cf..ed44ab124dc 100644 --- a/cpp/ql/test/header-variant-tests/deduplication/classes.ql +++ b/cpp/ql/test/header-variant-tests/deduplication/classes.ql @@ -1,4 +1,4 @@ -import default +import cpp from Class c, string n where n = count(Class x | x.getName() = c.getName()) + " distinct class(es) called " + c.getName() diff --git a/cpp/ql/test/library-tests/allocators/allocators.ql b/cpp/ql/test/library-tests/allocators/allocators.ql index 235ec0451e7..a2126cdfbce 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.ql +++ b/cpp/ql/test/library-tests/allocators/allocators.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.models.implementations.Allocation query predicate newExprs( diff --git a/cpp/ql/test/library-tests/blocks/cpp/exprs.expected b/cpp/ql/test/library-tests/blocks/cpp/exprs.expected index f81990f2c4b..5771a100263 100644 --- a/cpp/ql/test/library-tests/blocks/cpp/exprs.expected +++ b/cpp/ql/test/library-tests/blocks/cpp/exprs.expected @@ -79,4 +79,4 @@ | blocks.cpp:57:12:57:32 | call to expression | | blocks.cpp:57:14:57:30 | ^ { ... } | | blocks.cpp:57:23:57:26 | four | -| file://:0:0:0:0 | this | +| blocks.cpp:57:23:57:26 | this | diff --git a/cpp/ql/test/library-tests/builtins/edg/expr.expected b/cpp/ql/test/library-tests/builtins/edg/expr.expected index 7b4a51f022b..0969dc1e217 100644 --- a/cpp/ql/test/library-tests/builtins/edg/expr.expected +++ b/cpp/ql/test/library-tests/builtins/edg/expr.expected @@ -1,5 +1,8 @@ | edg.c:12:14:12:51 | (int)... | 0 | 0 | | edg.c:12:14:12:51 | __builtin_offsetof | 1 | 1 | +| edg.c:12:14:12:51 | mystruct | 0 | 0 | +| edg.c:12:49:12:50 | 0 | 0 | 0 | +| edg.c:12:49:12:50 | * ... | 0 | 0 | | edg.c:12:49:12:50 | f2 | 0 | 0 | | edg.c:13:14:13:45 | 0 | 0 | 0 | | edg.c:13:14:13:45 | & ... | 0 | 0 | @@ -10,6 +13,3 @@ | edg.c:13:14:13:45 | (size_t)... | 0 | 0 | | edg.c:13:14:13:45 | __INTADDR__ | 1 | 1 | | edg.c:13:43:13:44 | f2 | 0 | 0 | -| file://:0:0:0:0 | 0 | 0 | 0 | -| file://:0:0:0:0 | * ... | 0 | 0 | -| file://:0:0:0:0 | mystruct | 0 | 0 | diff --git a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected index 6166de5a80d..47918496198 100644 --- a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected +++ b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected @@ -1,298 +1,298 @@ | file://:0:0:0:0 | 0 | | 0 | | file://:0:0:0:0 | 1 | | 1 | | file://:0:0:0:0 | 2 | | 2 | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C4 | | | -| file://:0:0:0:0 | C4 | | | -| file://:0:0:0:0 | C5 | | | -| file://:0:0:0:0 | C5 | | | -| file://:0:0:0:0 | a_final_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct_plus | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | data | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_noexcept_destructor | | | -| file://:0:0:0:0 | has_noexcept_destructor | | | -| file://:0:0:0:0 | has_nothrow_assign | | | -| file://:0:0:0:0 | has_nothrow_assign | | | -| file://:0:0:0:0 | has_nothrow_constructor | | | -| file://:0:0:0:0 | has_nothrow_constructor | | | -| file://:0:0:0:0 | has_nothrow_copy | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_virtual_destructor | | | -| file://:0:0:0:0 | has_virtual_destructor | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method_data | | | -| file://:0:0:0:0 | no_has_nothrow_constructor | | | -| file://:0:0:0:0 | no_has_nothrow_constructor | | | | ms.cpp:38:41:38:45 | 0 | | 0 | | ms.cpp:88:27:88:45 | __has_assign | empty | 0 | +| ms.cpp:88:27:88:45 | empty | | | | ms.cpp:89:27:89:50 | __has_assign | has_assign | 1 | +| ms.cpp:89:27:89:50 | has_assign | | | | ms.cpp:91:25:91:41 | __has_copy | empty | 0 | +| ms.cpp:91:25:91:41 | empty | | | | ms.cpp:92:25:92:44 | __has_copy | has_copy | 1 | +| ms.cpp:92:25:92:44 | has_copy | | | | ms.cpp:94:35:94:61 | __has_nothrow_assign | empty | 1 | +| ms.cpp:94:35:94:61 | empty | | | | ms.cpp:95:35:95:66 | __has_nothrow_assign | has_assign | 0 | +| ms.cpp:95:35:95:66 | has_assign | | | | ms.cpp:96:35:96:74 | __has_nothrow_assign | has_nothrow_assign | 1 | +| ms.cpp:96:35:96:74 | has_nothrow_assign | | | | ms.cpp:98:40:98:71 | __has_nothrow_constructor | empty | 1 | +| ms.cpp:98:40:98:71 | empty | | | | ms.cpp:99:40:99:92 | __has_nothrow_constructor | no_has_nothrow_constructor | 0 | +| ms.cpp:99:40:99:92 | no_has_nothrow_constructor | | | | ms.cpp:100:40:100:89 | __has_nothrow_constructor | has_nothrow_constructor | 1 | +| ms.cpp:100:40:100:89 | has_nothrow_constructor | | | | ms.cpp:102:33:102:57 | __has_nothrow_copy | empty | 1 | +| ms.cpp:102:33:102:57 | empty | | | | ms.cpp:103:33:103:60 | __has_nothrow_copy | has_copy | 0 | +| ms.cpp:103:33:103:60 | has_copy | | | | ms.cpp:104:33:104:68 | __has_nothrow_copy | has_nothrow_copy | 1 | +| ms.cpp:104:33:104:68 | has_nothrow_copy | | | | ms.cpp:106:35:106:61 | __has_trivial_assign | empty | 1 | +| ms.cpp:106:35:106:61 | empty | | | | ms.cpp:107:35:107:66 | __has_trivial_assign | has_assign | 0 | +| ms.cpp:107:35:107:66 | has_assign | | | | ms.cpp:109:40:109:71 | __has_trivial_constructor | empty | 1 | +| ms.cpp:109:40:109:71 | empty | | | | ms.cpp:110:40:110:92 | __has_trivial_constructor | no_has_nothrow_constructor | 0 | +| ms.cpp:110:40:110:92 | no_has_nothrow_constructor | | | | ms.cpp:111:40:111:89 | __has_trivial_constructor | has_nothrow_constructor | 0 | +| ms.cpp:111:40:111:89 | has_nothrow_constructor | | | | ms.cpp:113:33:113:57 | __has_trivial_copy | empty | 1 | +| ms.cpp:113:33:113:57 | empty | | | | ms.cpp:114:33:114:60 | __has_trivial_copy | has_copy | 0 | +| ms.cpp:114:33:114:60 | has_copy | | | | ms.cpp:116:36:116:63 | __has_user_destructor | empty | 0 | +| ms.cpp:116:36:116:63 | empty | | | | ms.cpp:117:36:117:77 | __has_user_destructor | has_user_destructor | 1 | +| ms.cpp:117:36:117:77 | has_user_destructor | | | | ms.cpp:118:36:118:80 | __has_user_destructor | has_virtual_destructor | 1 | +| ms.cpp:118:36:118:80 | has_virtual_destructor | | | | ms.cpp:120:39:120:69 | __has_virtual_destructor | empty | 0 | +| ms.cpp:120:39:120:69 | empty | | | | ms.cpp:121:39:121:83 | __has_virtual_destructor | has_user_destructor | 0 | +| ms.cpp:121:39:121:83 | has_user_destructor | | | | ms.cpp:122:39:122:86 | __has_virtual_destructor | has_virtual_destructor | 1 | +| ms.cpp:122:39:122:86 | has_virtual_destructor | | | | ms.cpp:124:28:124:47 | __is_abstract | empty | 0 | +| ms.cpp:124:28:124:47 | empty | | | | ms.cpp:125:28:125:50 | __is_abstract | abstract | 1 | +| ms.cpp:125:28:125:50 | abstract | | | | ms.cpp:126:28:126:48 | __is_abstract | method | 0 | +| ms.cpp:126:28:126:48 | method | | | +| ms.cpp:128:27:128:45 | C1 | | | +| ms.cpp:128:27:128:45 | C1 | | | | ms.cpp:128:27:128:45 | __is_base_of | C1,C1 | 1 | +| ms.cpp:129:27:129:45 | C1 | | | +| ms.cpp:129:27:129:45 | C2 | | | | ms.cpp:129:27:129:45 | __is_base_of | C1,C2 | 1 | +| ms.cpp:130:27:130:45 | C1 | | | +| ms.cpp:130:27:130:45 | C3 | | | | ms.cpp:130:27:130:45 | __is_base_of | C1,C3 | 1 | +| ms.cpp:131:27:131:45 | C1 | | | +| ms.cpp:131:27:131:45 | C5 | | | | ms.cpp:131:27:131:45 | __is_base_of | C1,C5 | 0 | +| ms.cpp:132:27:132:45 | C2 | | | +| ms.cpp:132:27:132:45 | C3 | | | | ms.cpp:132:27:132:45 | __is_base_of | C3,C2 | 0 | +| ms.cpp:133:27:133:45 | C1 | | | +| ms.cpp:133:27:133:45 | C3 | | | | ms.cpp:133:27:133:45 | __is_base_of | C3,C1 | 0 | +| ms.cpp:134:27:134:45 | C2 | | | +| ms.cpp:134:27:134:45 | C4 | | | | ms.cpp:134:27:134:45 | __is_base_of | C2,C4 | 0 | | ms.cpp:135:27:135:47 | __is_base_of | int,int | 0 | +| ms.cpp:135:27:135:47 | int | | | +| ms.cpp:135:27:135:47 | int | | | | ms.cpp:136:27:136:48 | __is_base_of | int,long | 0 | +| ms.cpp:136:27:136:48 | int | | | +| ms.cpp:136:27:136:48 | long | | | | ms.cpp:137:28:137:49 | __is_base_of | long,int | 0 | +| ms.cpp:137:28:137:49 | int | | | +| ms.cpp:137:28:137:49 | long | | | | ms.cpp:138:28:138:51 | __is_base_of | int,double | 0 | +| ms.cpp:138:28:138:51 | double | | | +| ms.cpp:138:28:138:51 | int | | | | ms.cpp:139:28:139:51 | __is_base_of | double,int | 0 | +| ms.cpp:139:28:139:51 | double | | | +| ms.cpp:139:28:139:51 | int | | | | ms.cpp:141:25:141:41 | __is_class | empty | 1 | +| ms.cpp:141:25:141:41 | empty | | | | ms.cpp:142:25:142:43 | __is_class | an_enum | 0 | +| ms.cpp:142:25:142:43 | an_enum | | | | ms.cpp:143:25:143:43 | __is_class | a_union | 0 | +| ms.cpp:143:25:143:43 | a_union | | | | ms.cpp:144:25:144:44 | __is_class | a_struct | 1 | +| ms.cpp:144:25:144:44 | a_struct | | | | ms.cpp:145:25:145:39 | __is_class | int | 0 | +| ms.cpp:145:25:145:39 | int | | | +| ms.cpp:147:34:147:59 | C1 | | | +| ms.cpp:147:34:147:59 | C1 | | | | ms.cpp:147:34:147:59 | __is_convertible_to | C1,C1 | 1 | +| ms.cpp:148:34:148:59 | C1 | | | +| ms.cpp:148:34:148:59 | C2 | | | | ms.cpp:148:34:148:59 | __is_convertible_to | C1,C2 | 0 | +| ms.cpp:149:34:149:59 | C1 | | | +| ms.cpp:149:34:149:59 | C3 | | | | ms.cpp:149:34:149:59 | __is_convertible_to | C1,C3 | 0 | +| ms.cpp:150:34:150:59 | C1 | | | +| ms.cpp:150:34:150:59 | C5 | | | | ms.cpp:150:34:150:59 | __is_convertible_to | C1,C5 | 0 | +| ms.cpp:151:34:151:59 | C2 | | | +| ms.cpp:151:34:151:59 | C3 | | | | ms.cpp:151:34:151:59 | __is_convertible_to | C3,C2 | 0 | +| ms.cpp:152:34:152:59 | C1 | | | +| ms.cpp:152:34:152:59 | C3 | | | | ms.cpp:152:34:152:59 | __is_convertible_to | C3,C1 | 0 | +| ms.cpp:153:34:153:59 | C2 | | | +| ms.cpp:153:34:153:59 | C4 | | | | ms.cpp:153:34:153:59 | __is_convertible_to | C2,C4 | 0 | | ms.cpp:154:34:154:61 | __is_convertible_to | int,int | 1 | +| ms.cpp:154:34:154:61 | int | | | +| ms.cpp:154:34:154:61 | int | | | | ms.cpp:155:34:155:62 | __is_convertible_to | int,long | 1 | +| ms.cpp:155:34:155:62 | int | | | +| ms.cpp:155:34:155:62 | long | | | | ms.cpp:156:35:156:63 | __is_convertible_to | long,int | 1 | +| ms.cpp:156:35:156:63 | int | | | +| ms.cpp:156:35:156:63 | long | | | | ms.cpp:157:35:157:65 | __is_convertible_to | int,double | 1 | +| ms.cpp:157:35:157:65 | double | | | +| ms.cpp:157:35:157:65 | int | | | | ms.cpp:158:35:158:65 | __is_convertible_to | double,int | 1 | +| ms.cpp:158:35:158:65 | double | | | +| ms.cpp:158:35:158:65 | int | | | | ms.cpp:160:25:160:41 | __is_empty | empty | 1 | +| ms.cpp:160:25:160:41 | empty | | | | ms.cpp:161:25:161:42 | __is_empty | method | 1 | +| ms.cpp:161:25:161:42 | method | | | | ms.cpp:162:25:162:40 | __is_empty | data | 0 | +| ms.cpp:162:25:162:40 | data | | | | ms.cpp:163:25:163:47 | __is_empty | method_data | 0 | +| ms.cpp:163:25:163:47 | method_data | | | | ms.cpp:164:25:164:44 | __is_empty | abstract | 0 | +| ms.cpp:164:25:164:44 | abstract | | | | ms.cpp:166:24:166:39 | __is_enum | empty | 0 | +| ms.cpp:166:24:166:39 | empty | | | | ms.cpp:167:24:167:41 | __is_enum | an_enum | 1 | +| ms.cpp:167:24:167:41 | an_enum | | | | ms.cpp:168:24:168:41 | __is_enum | a_union | 0 | +| ms.cpp:168:24:168:41 | a_union | | | | ms.cpp:170:31:170:53 | __is_polymorphic | empty | 0 | +| ms.cpp:170:31:170:53 | empty | | | | ms.cpp:171:31:171:56 | __is_polymorphic | abstract | 1 | +| ms.cpp:171:31:171:56 | abstract | | | | ms.cpp:172:31:172:54 | __is_polymorphic | method | 0 | +| ms.cpp:172:31:172:54 | method | | | | ms.cpp:174:25:174:41 | __is_union | empty | 0 | +| ms.cpp:174:25:174:41 | empty | | | | ms.cpp:175:25:175:43 | __is_union | an_enum | 0 | +| ms.cpp:175:25:175:43 | an_enum | | | | ms.cpp:176:25:176:43 | __is_union | a_union | 1 | +| ms.cpp:176:25:176:43 | a_union | | | | ms.cpp:177:25:177:44 | __is_union | a_struct | 0 | +| ms.cpp:177:25:177:44 | a_struct | | | | ms.cpp:178:25:178:39 | __is_union | int | 0 | +| ms.cpp:178:25:178:39 | int | | | | ms.cpp:180:42:180:79 | __is_trivially_constructible | a_struct | 1 | +| ms.cpp:180:42:180:79 | a_struct | | | | ms.cpp:181:42:181:76 | __is_trivially_constructible | empty | 1 | +| ms.cpp:181:42:181:76 | empty | | | | ms.cpp:182:42:182:79 | __is_trivially_constructible | has_copy | 0 | +| ms.cpp:182:42:182:79 | has_copy | | | | ms.cpp:184:31:184:57 | __is_destructible | a_struct | 1 | +| ms.cpp:184:31:184:57 | a_struct | | | | ms.cpp:185:31:185:54 | __is_destructible | empty | 1 | +| ms.cpp:185:31:185:54 | empty | | | | ms.cpp:186:31:186:57 | __is_destructible | has_copy | 1 | +| ms.cpp:186:31:186:57 | has_copy | | | | ms.cpp:187:31:187:68 | __is_destructible | has_user_destructor | 0 | +| ms.cpp:187:31:187:68 | has_user_destructor | | | | ms.cpp:189:39:189:73 | __is_nothrow_destructible | a_struct | 1 | +| ms.cpp:189:39:189:73 | a_struct | | | | ms.cpp:190:39:190:70 | __is_nothrow_destructible | empty | 1 | +| ms.cpp:190:39:190:70 | empty | | | | ms.cpp:191:39:191:73 | __is_nothrow_destructible | has_copy | 1 | +| ms.cpp:191:39:191:73 | has_copy | | | | ms.cpp:192:39:192:84 | __is_nothrow_destructible | has_user_destructor | 0 | +| ms.cpp:192:39:192:84 | has_user_destructor | | | | ms.cpp:193:39:193:88 | __is_nothrow_destructible | has_noexcept_destructor | 0 | +| ms.cpp:193:39:193:88 | has_noexcept_destructor | | | | ms.cpp:195:41:195:77 | __is_trivially_destructible | a_struct | 1 | +| ms.cpp:195:41:195:77 | a_struct | | | | ms.cpp:196:41:196:74 | __is_trivially_destructible | empty | 1 | +| ms.cpp:196:41:196:74 | empty | | | | ms.cpp:197:41:197:77 | __is_trivially_destructible | has_copy | 1 | +| ms.cpp:197:41:197:77 | has_copy | | | | ms.cpp:198:41:198:88 | __is_trivially_destructible | has_user_destructor | 0 | +| ms.cpp:198:41:198:88 | has_user_destructor | | | | ms.cpp:199:41:199:92 | __is_trivially_destructible | has_noexcept_destructor | 0 | +| ms.cpp:199:41:199:92 | has_noexcept_destructor | | | | ms.cpp:201:39:201:82 | __is_trivially_assignable | a_struct,a_struct | 1 | +| ms.cpp:201:39:201:82 | a_struct | | | +| ms.cpp:201:39:201:82 | a_struct | | | | ms.cpp:202:39:202:79 | __is_trivially_assignable | a_struct,empty | 0 | +| ms.cpp:202:39:202:79 | a_struct | | | +| ms.cpp:202:39:202:79 | empty | | | | ms.cpp:203:39:203:77 | __is_trivially_assignable | a_struct,int | 0 | +| ms.cpp:203:39:203:77 | a_struct | | | +| ms.cpp:203:39:203:77 | int | | | | ms.cpp:205:37:205:78 | __is_nothrow_assignable | a_struct,a_struct | 1 | +| ms.cpp:205:37:205:78 | a_struct | | | +| ms.cpp:205:37:205:78 | a_struct | | | | ms.cpp:206:37:206:75 | __is_nothrow_assignable | a_struct,empty | 0 | +| ms.cpp:206:37:206:75 | a_struct | | | +| ms.cpp:206:37:206:75 | empty | | | | ms.cpp:207:37:207:73 | __is_nothrow_assignable | a_struct,int | 0 | +| ms.cpp:207:37:207:73 | a_struct | | | +| ms.cpp:207:37:207:73 | int | | | | ms.cpp:209:34:209:63 | __is_standard_layout | a_struct | 1 | +| ms.cpp:209:34:209:63 | a_struct | | | | ms.cpp:210:34:210:68 | __is_standard_layout | a_struct_plus | 0 | +| ms.cpp:210:34:210:68 | a_struct_plus | | | | ms.cpp:212:37:212:66 | __is_trivially_copyable | empty | 1 | +| ms.cpp:212:37:212:66 | empty | | | | ms.cpp:213:37:213:69 | __is_trivially_copyable | has_copy | 0 | +| ms.cpp:213:37:213:69 | has_copy | | | | ms.cpp:215:31:215:54 | __is_literal_type | empty | 1 | +| ms.cpp:215:31:215:54 | empty | | | | ms.cpp:216:31:216:68 | __is_literal_type | has_user_destructor | 0 | +| ms.cpp:216:31:216:68 | has_user_destructor | | | | ms.cpp:218:44:218:80 | __has_trivial_move_constructor | empty | 1 | +| ms.cpp:218:44:218:80 | empty | | | | ms.cpp:219:44:219:83 | __has_trivial_move_constructor | has_copy | 0 | +| ms.cpp:219:44:219:83 | has_copy | | | | ms.cpp:220:44:220:94 | __has_trivial_move_constructor | has_user_destructor | 1 | +| ms.cpp:220:44:220:94 | has_user_destructor | | | | ms.cpp:222:39:222:70 | __has_trivial_move_assign | empty | 1 | +| ms.cpp:222:39:222:70 | empty | | | | ms.cpp:223:39:223:73 | __has_trivial_move_assign | has_copy | 1 | +| ms.cpp:223:39:223:73 | has_copy | | | | ms.cpp:224:39:224:75 | __has_trivial_move_assign | has_assign | 0 | +| ms.cpp:224:39:224:75 | has_assign | | | | ms.cpp:226:39:226:70 | __has_nothrow_move_assign | empty | 1 | +| ms.cpp:226:39:226:70 | empty | | | | ms.cpp:227:39:227:73 | __has_nothrow_move_assign | has_copy | 1 | +| ms.cpp:227:39:227:73 | has_copy | | | | ms.cpp:228:39:228:75 | __has_nothrow_move_assign | has_assign | 0 | +| ms.cpp:228:39:228:75 | has_assign | | | | ms.cpp:229:39:229:83 | __has_nothrow_move_assign | has_nothrow_assign | 1 | +| ms.cpp:229:39:229:83 | has_nothrow_assign | | | | ms.cpp:231:32:231:54 | __is_constructible | int | 1 | +| ms.cpp:231:32:231:54 | int | | | | ms.cpp:232:32:232:60 | __is_constructible | int,float | 1 | +| ms.cpp:232:32:232:60 | float | | | +| ms.cpp:232:32:232:60 | int | | | | ms.cpp:233:32:233:66 | __is_constructible | int,float,float | 0 | +| ms.cpp:233:32:233:66 | float | | | +| ms.cpp:233:32:233:66 | float | | | +| ms.cpp:233:32:233:66 | int | | | | ms.cpp:235:40:235:70 | __is_nothrow_constructible | int | 1 | +| ms.cpp:235:40:235:70 | int | | | | ms.cpp:236:40:236:76 | __is_nothrow_constructible | int,float | 1 | +| ms.cpp:236:40:236:76 | float | | | +| ms.cpp:236:40:236:76 | int | | | | ms.cpp:237:40:237:82 | __is_nothrow_constructible | int,float,float | 0 | +| ms.cpp:237:40:237:82 | float | | | +| ms.cpp:237:40:237:82 | float | | | +| ms.cpp:237:40:237:82 | int | | | | ms.cpp:239:29:239:50 | __has_finalizer | empty | 0 | +| ms.cpp:239:29:239:50 | empty | | | | ms.cpp:241:27:241:46 | __is_delegate | empty | 0 | +| ms.cpp:241:27:241:46 | empty | | | | ms.cpp:243:34:243:60 | __is_interface_class | empty | 0 | +| ms.cpp:243:34:243:60 | empty | | | | ms.cpp:245:28:245:48 | __is_ref_array | empty | 0 | +| ms.cpp:245:28:245:48 | empty | | | | ms.cpp:247:28:247:48 | __is_ref_class | empty | 0 | +| ms.cpp:247:28:247:48 | empty | | | | ms.cpp:249:25:249:42 | __is_sealed | empty | 0 | +| ms.cpp:249:25:249:42 | empty | | | | ms.cpp:251:37:251:66 | __is_simple_value_class | empty | 0 | +| ms.cpp:251:37:251:66 | empty | | | | ms.cpp:253:30:253:52 | __is_value_class | empty | 0 | +| ms.cpp:253:30:253:52 | empty | | | | ms.cpp:255:24:255:43 | __is_final | a_struct | 0 | +| ms.cpp:255:24:255:43 | a_struct | | | | ms.cpp:256:24:256:49 | __is_final | a_final_struct | 1 | +| ms.cpp:256:24:256:49 | a_final_struct | | | diff --git a/cpp/ql/test/library-tests/classes/variadic/expr.expected b/cpp/ql/test/library-tests/classes/variadic/expr.expected index acc511a45fa..a3b685781e3 100644 --- a/cpp/ql/test/library-tests/classes/variadic/expr.expected +++ b/cpp/ql/test/library-tests/classes/variadic/expr.expected @@ -1,6 +1,6 @@ | file://:0:0:0:0 | 0 | -| file://:0:0:0:0 | this | | test.cpp:4:9:4:9 | call to f | | test.cpp:4:9:4:9 | f | +| test.cpp:4:9:4:9 | this | | test.cpp:4:9:4:11 | call to expression | | test.cpp:10:5:10:11 | call to Foo | diff --git a/cpp/ql/test/library-tests/complex_numbers/expr.ql b/cpp/ql/test/library-tests/complex_numbers/expr.ql index 0f2e6f14d4e..83c6dca9c64 100644 --- a/cpp/ql/test/library-tests/complex_numbers/expr.ql +++ b/cpp/ql/test/library-tests/complex_numbers/expr.ql @@ -1,4 +1,4 @@ import cpp from Expr e -select e, e.getCanonicalQLClass() +select e, e.getAPrimaryQlClass() diff --git a/cpp/ql/test/library-tests/conditions/elements.expected b/cpp/ql/test/library-tests/conditions/elements.expected index 1e2ca174e66..b08b30db718 100644 --- a/cpp/ql/test/library-tests/conditions/elements.expected +++ b/cpp/ql/test/library-tests/conditions/elements.expected @@ -1,7 +1,6 @@ | file://:0:0:0:0 | | | file://:0:0:0:0 | (global namespace) | | file://:0:0:0:0 | | -| file://:0:0:0:0 | | | file://:0:0:0:0 | | | file://:0:0:0:0 | There was an error during this compilation | | file://:0:0:0:0 | _Complex __float128 | @@ -125,6 +124,7 @@ | test.cpp:2:10:4:1 | { ... } | | test.cpp:3:5:3:15 | if (...) ... | | test.cpp:3:9:3:12 | (condition decl) | +| test.cpp:3:9:3:12 | | | test.cpp:3:12:3:12 | | | test.cpp:3:12:3:12 | a condition declaration must include an initializer | | test.cpp:3:12:3:12 | declaration of | diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected index 110fb218b5f..524a74155c0 100644 --- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -551,7 +551,7 @@ irGuardsControl | test.c:146:8:146:8 | Load: x | false | 147 | 147 | | test.c:152:10:152:10 | Load: x | true | 152 | 152 | | test.c:152:15:152:15 | Load: y | true | 152 | 152 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 0 | 0 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 19 | 19 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | false | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 30 | 30 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 32 | 32 | @@ -690,8 +690,8 @@ irGuardsEnsure | test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 113 | 113 | | test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | test.c:109:23:109:23 | Constant: (long)... | 0 | 113 | 113 | | test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:23:109:23 | Constant: (long)... | < | test.c:109:19:109:19 | Load: y | 1 | 113 | 113 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 0 | 0 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 0 | 0 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 19 | 19 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 19 | 19 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | test.cpp:31:12:31:13 | Constant: - ... | 0 | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 30 | 30 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 32 | 32 | diff --git a/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected b/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected index 33461214a5f..d5f83c75d06 100644 --- a/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected +++ b/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected @@ -2,14 +2,8 @@ | | cpp_range_based_for | 0 | 1 | file://:0:0:0:0 | (reference dereference) | | | | cpp_range_based_for | 0 | 1 | file://:0:0:0:0 | (reference to) | | | | cpp_range_based_for | 0 | 9 | file://:0:0:0:0 | initializer for (__range) | declaration | -| | cpp_range_based_for | 0 | 11 | file://:0:0:0:0 | (__range) | call to begin | | | cpp_range_based_for | 0 | 13 | file://:0:0:0:0 | initializer for (__begin) | (__range) | -| | cpp_range_based_for | 0 | 14 | file://:0:0:0:0 | (__range) | call to end | | | cpp_range_based_for | 0 | 16 | file://:0:0:0:0 | initializer for (__end) | (__end) | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator!= | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator* | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator++ | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__end) | (__begin) | | cpp | CopyConstructorClass | 28 | 1 | cpp.cpp:28:5:28:24 | CopyConstructorClass | | | cpp | CopyConstructorClass | 30 | 1 | cpp.cpp:30:5:30:24 | CopyConstructorClass | | | cpp | IntVectorIter | 4 | 1 | cpp.cpp:4:7:4:7 | IntVectorIter | | @@ -37,10 +31,16 @@ | cpp | cpp_range_based_for | 22 | 7 | cpp.cpp:22:5:23:12 | declaration | vec | | cpp | cpp_range_based_for | 22 | 8 | cpp.cpp:22:18:22:20 | vec | initializer for (__range) | | cpp | cpp_range_based_for | 22 | 10 | cpp.cpp:22:5:23:12 | declaration | (__range) | +| cpp | cpp_range_based_for | 22 | 11 | cpp.cpp:22:18:22:18 | (__range) | call to begin | | cpp | cpp_range_based_for | 22 | 12 | cpp.cpp:22:18:22:18 | call to begin | initializer for (__begin) | +| cpp | cpp_range_based_for | 22 | 14 | cpp.cpp:22:18:22:18 | (__range) | call to end | | cpp | cpp_range_based_for | 22 | 15 | cpp.cpp:22:18:22:18 | call to end | initializer for (__end) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:5:23:12 | declaration | (__begin) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:14:22:14 | initializer for i | ExprStmt | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator!= | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator* | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator++ | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__end) | (__begin) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator!= | return ... | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator!= | declaration | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator* | initializer for i | diff --git a/cpp/ql/test/library-tests/conversions/sanity.expected b/cpp/ql/test/library-tests/conversions/consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/conversions/sanity.expected rename to cpp/ql/test/library-tests/conversions/consistency.expected diff --git a/cpp/ql/test/library-tests/conversions/consistency.qlref b/cpp/ql/test/library-tests/conversions/consistency.qlref new file mode 100644 index 00000000000..183c1b1ffe1 --- /dev/null +++ b/cpp/ql/test/library-tests/conversions/consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ASTConsistency.ql diff --git a/cpp/ql/test/library-tests/conversions/conversions.ql b/cpp/ql/test/library-tests/conversions/conversions.ql index 6ba2bd8f365..c26881ecbbe 100644 --- a/cpp/ql/test/library-tests/conversions/conversions.ql +++ b/cpp/ql/test/library-tests/conversions/conversions.ql @@ -1,4 +1,4 @@ -import default +import cpp string getValueCategoryString(Expr expr) { if expr.isLValueCategory() diff --git a/cpp/ql/test/library-tests/conversions/sanity.qlref b/cpp/ql/test/library-tests/conversions/sanity.qlref deleted file mode 100644 index 50d6aaf2188..00000000000 --- a/cpp/ql/test/library-tests/conversions/sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ASTSanity.ql diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 25fbdba93c1..9836f7fb20d 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -1,13 +1,13 @@ -int atoi(const char *nptr); -char *getenv(const char *name); -char *strcat(char * s1, const char * s2); +#include "shared.h" + + + + + + + -char *strdup(const char *); -char *_strdup(const char *); -char *unmodeled_function(const char *); -void sink(const char *); -void sink(int); int main(int argc, char *argv[]) { @@ -96,4 +96,56 @@ void test_outparams() { char *p2 = nullptr; flow_to_outparam(&p2, getenv("VAR")); sink(p2); // tainted -} \ No newline at end of file +} + + + + +struct XY { + int x; + int y; +}; + +void taint_y(XY *xyp) { + int tainted = getenv("VAR")[0]; + xyp->y = tainted; +} + +void test_conflated_fields3() { + XY xy; + xy.x = 0; + taint_y(&xy); + sink(xy.x); // not tainted +} + +struct Point { + int x; + int y; + + void callSink() { + sink(this->x); // tainted + sink(this->y); // not tainted + } +}; + +void test_conflated_fields1() { + Point p; + p.x = getenv("VAR")[0]; + sink(p.x); // tainted + sink(p.y); // not tainted + p.callSink(); +} + +void taint_x(Point *pp) { + pp->x = getenv("VAR")[0]; +} + +void y_to_sink(Point *pp) { + sink(pp->y); // not tainted +} + +void test_conflated_fields2() { + Point p; + taint_x(&p); + y_to_sink(&p); +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp new file mode 100644 index 00000000000..929983d05f7 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp @@ -0,0 +1,35 @@ +#include "shared.h" + +using SinkFunction = void (*)(int); + +void notSink(int notSinkParam); + +void callsSink(int sinkParam) { + sink(sinkParam); +} + +struct { + SinkFunction sinkPtr, notSinkPtr; +} globalStruct; + +union { + SinkFunction sinkPtr, notSinkPtr; +} globalUnion; + +SinkFunction globalSinkPtr; + +void assignGlobals() { + globalStruct.sinkPtr = callsSink; + globalUnion.sinkPtr = callsSink; + globalSinkPtr = callsSink; +}; + +void testStruct() { + globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam [NOT DETECTED] + globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // shouldn't reach sinkParam + + globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam + globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam + + globalSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected index 520ebcbff1f..5dec31c1458 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected @@ -1,4 +1,6 @@ -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | global1 | +| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | (const char *)... | global1 | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | global1 | global1 | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | global2 | +| globals.cpp:13:15:13:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global1 | +| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | (const char *)... | global2 | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | global2 | global2 | +| globals.cpp:23:15:23:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global2 | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp index 54e0718ceef..9f598a8c615 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp @@ -1,5 +1,5 @@ -char * getenv(const char *); -void sink(char *sinkParam); +#include "shared.h" + void throughLocal() { char * local = getenv("VAR"); diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h new file mode 100644 index 00000000000..0c29c16239c --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h @@ -0,0 +1,14 @@ +// Common declarations in this test dir should go in this file. Otherwise, some +// declarations will have multiple locations, which leads to confusing test +// output. + +void sink(const char *sinkparam); +void sink(int sinkparam); + +int atoi(const char *nptr); +char *getenv(const char *name); +char *strcat(char * s1, const char * s2); + +char *strdup(const char *string); +char *_strdup(const char *string); +char *unmodeled_function(const char *const_string); diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp new file mode 100644 index 00000000000..3786e31a9ee --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp @@ -0,0 +1,159 @@ + +#include "shared.h" + +typedef unsigned long size_t; + +namespace std +{ + template struct char_traits; + + typedef size_t streamsize; + + template class allocator { + public: + allocator() throw(); + }; + + template, class Allocator = allocator > + class basic_string { + public: + explicit basic_string(const Allocator& a = Allocator()); + basic_string(const charT* s, const Allocator& a = Allocator()); + + const charT* c_str() const; + }; + + typedef basic_string string; + + template > + class basic_istream /*: virtual public basic_ios - not needed for this test */ { + public: + basic_istream& operator>>(int& n); + }; + + template > + class basic_ostream /*: virtual public basic_ios - not needed for this test */ { + public: + typedef charT char_type; + basic_ostream& write(const char_type* s, streamsize n); + + basic_ostream& operator<<(int n); + }; + + template basic_ostream& operator<<(basic_ostream&, const charT*); + template basic_ostream& operator<<(basic_ostream& os, const basic_string& str); + + template> + class basic_iostream : public basic_istream, public basic_ostream { + public: + }; + + template, class Allocator = allocator> + class basic_stringstream : public basic_iostream { + public: + explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/); + + basic_string str() const; + }; + + using stringstream = basic_stringstream; +} + +char *source() { return getenv("USERDATA"); } +void sink(const std::string &s) {}; +void sink(const std::stringstream &s) {}; + +void test_string() +{ + char *a = source(); + std::string b("123"); + std::string c(source()); + + sink(a); // tainted + sink(b); + sink(c); // tainted [NOT DETECTED] + sink(b.c_str()); + sink(c.c_str()); // tainted [NOT DETECTED] +} + +void test_stringstream() +{ + std::stringstream ss1, ss2, ss3, ss4, ss5; + std::string t(source()); + + ss1 << "1234"; + ss2 << source(); + ss3 << "123" << source(); + ss4 << source() << "456"; + ss5 << t; + + sink(ss1); + sink(ss2); // tainted [NOT DETECTED] + sink(ss3); // tainted [NOT DETECTED] + sink(ss4); // tainted [NOT DETECTED] + sink(ss5); // tainted [NOT DETECTED] + sink(ss1.str()); + sink(ss2.str()); // tainted [NOT DETECTED] + sink(ss3.str()); // tainted [NOT DETECTED] + sink(ss4.str()); // tainted [NOT DETECTED] + sink(ss5.str()); // tainted [NOT DETECTED] +} + +void test_stringstream_int(int source) +{ + std::stringstream ss1, ss2; + + ss1 << 1234; + ss2 << source; + + sink(ss1); + sink(ss2); // tainted [NOT DETECTED] + sink(ss1.str()); + sink(ss2.str()); // tainted [NOT DETECTED] +} + +using namespace std; + +char *user_input() { + return source(); +} + +void sink(const char *filename, const char *mode); + +void test_strings2() +{ + string path1 = user_input(); + sink(path1.c_str(), "r"); // tainted [NOT DETECTED] + + string path2; + path2 = user_input(); + sink(path2.c_str(), "r"); // tainted + + string path3(user_input()); + sink(path3.c_str(), "r"); // tainted [NOT DETECTED] +} + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted [NOT DETECTED] +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted [NOT DETECTED] + sink(ss); // tainted [NOT DETECTED] +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 4f98b1bead0..e0c97fb5270 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -1,22 +1,18 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:6:15:6:24 | p#0 | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:5:14:5:23 | p#0 | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:13:27:13:32 | string | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:7:26:7:35 | p#0 | +| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:12:26:12:31 | string | | defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:32 | call to getenv | | defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:38:3:39 | s2 | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:18:27:18:32 | call to getenv | shared.h:14:38:14:49 | const_string | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv | @@ -24,7 +20,8 @@ | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | +| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:10:38:10:39 | s2 | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | p#0 | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer | @@ -35,42 +32,37 @@ | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:15 | call to getenv | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:22 | (const char *)... | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:64:10:64:15 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:22 | call to getenv | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:29 | (const char *)... | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:66:17:66:22 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:33 | call to getenv | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:40 | (const char *)... | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:67:28:67:33 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:34 | call to getenv | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:41 | (const char *)... | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:68:29:68:34 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:38 | call to getenv | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:45 | (const char *)... | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | +| defaulttainttracking.cpp:69:33:69:38 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 | | defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:16 | call to getenv | @@ -87,54 +79,138 @@ | defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:39 | call to getenv | | defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:46 | (const char *)... | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:35 | call to getenv | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:42 | (const char *)... | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:79:30:79:35 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:84:17:84:17 | t | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:42:91:44 | arg | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:96:11:96:12 | p2 | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:97:27:97:32 | call to getenv | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | +| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:7:110:13 | tainted | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:22 | call to getenv | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:14 | call to getenv | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | (int)... | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | access to array | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... | +| dispatch.cpp:28:29:28:34 | call to getenv | shared.h:8:22:8:25 | nptr | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:27:29:30 | call to atoi | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:37 | call to getenv | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:48 | (const char *)... | +| dispatch.cpp:29:32:29:37 | call to getenv | shared.h:8:22:8:25 | nptr | +| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | +| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | +| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:23:31:26 | call to atoi | +| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:33 | call to getenv | +| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:44 | (const char *)... | +| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:8:22:8:25 | nptr | +| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | +| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | +| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:26:32:29 | call to atoi | +| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:36 | call to getenv | +| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:47 | (const char *)... | +| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:8:22:8:25 | nptr | +| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | +| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | +| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:17:34:20 | call to atoi | +| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:27 | call to getenv | +| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:38 | (const char *)... | +| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:8:22:8:25 | nptr | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:20:5:25 | call to getenv | +| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | (const char *)... | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | local | +| globals.cpp:5:20:5:25 | call to getenv | shared.h:5:23:5:31 | sinkparam | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:9:8:9:14 | global1 | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv | -| test_diff.cpp:92:10:92:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | +| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | access to array | -| test_diff.cpp:94:32:94:35 | argv | defaulttainttracking.cpp:10:11:10:13 | p#0 | -| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:2:11:2:13 | p#0 | +| test_diff.cpp:94:32:94:35 | argv | shared.h:6:15:6:23 | sinkparam | | test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:10:94:36 | reinterpret_cast... | | test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:32:94:35 | argv | -| test_diff.cpp:96:26:96:29 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:96:26:96:29 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:16:39:16:39 | a | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:17:10:17:10 | a | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:29 | argv | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | (const char *)... | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | access to array | -| test_diff.cpp:98:18:98:21 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:98:18:98:21 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:16:39:16:39 | a | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:17:10:17:10 | a | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p | @@ -148,15 +224,13 @@ | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | * ... | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:27 | p | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:30 | access to array | -| test_diff.cpp:104:12:104:15 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:104:12:104:15 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | (const char *)... | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | * ... | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:15 | argv | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:19 | ... + ... | -| test_diff.cpp:108:10:108:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:108:10:108:13 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:24:20:24:29 | p#0 | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:29:24:29:24 | p | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:30:14:30:14 | p | @@ -168,8 +242,7 @@ | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:13 | argv | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | (const char *)... | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | access to array | -| test_diff.cpp:115:11:115:14 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:115:11:115:14 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:24:20:24:29 | p#0 | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:41:24:41:24 | p | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:42:14:42:14 | p | @@ -184,8 +257,7 @@ | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:29 | argv | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | (const char *)... | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | access to array | -| test_diff.cpp:121:23:121:26 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:121:23:121:26 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:60:24:60:24 | p | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:61:34:61:34 | p | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:67:24:67:24 | p | @@ -193,8 +265,7 @@ | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:26 | argv | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | (const char *)... | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | access to array | -| test_diff.cpp:124:19:124:22 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:124:19:124:22 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:24:20:24:29 | p#0 | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:81:24:81:24 | p | @@ -202,16 +273,14 @@ | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:22 | argv | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | (const char *)... | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | access to array | -| test_diff.cpp:126:43:126:46 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:126:43:126:46 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:76:24:76:24 | p | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:81:24:81:24 | p | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:82:14:82:14 | p | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:46 | argv | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | (const char *)... | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | access to array | -| test_diff.cpp:128:44:128:47 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| test_diff.cpp:128:44:128:47 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:76:24:76:24 | p | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp index 0de1519c49a..49306f11e36 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp @@ -1,5 +1,5 @@ -void sink(const char *); -void sink(int); +#include "shared.h" + struct S { void(*f)(const char*); diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected index 858965a069b..2864260e017 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -1,34 +1,53 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | IR only | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | IR only | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only | +| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... | IR only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion | IR only | +| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:10:21:10:22 | s1 | AST only | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only | +| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:31:91:33 | ret | AST only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:5:92:8 | * ... | AST only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:6:92:8 | ret | AST only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:96:11:96:12 | p2 | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only | +| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | IR only | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:5:133:5 | x | AST only | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | IR only | +| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:7:140:7 | x | AST only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp | IR only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp | IR only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR only | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only | -| test_diff.cpp:111:10:111:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only | +| test_diff.cpp:111:10:111:13 | argv | shared.h:5:23:5:31 | sinkparam | AST only | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:29:24:29:24 | p | AST only | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp index 2fc2b9536f8..0ad17fb47af 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp @@ -27,7 +27,7 @@ void following_pointers( sourceStruct1_ptr->m1 = source(); sink(sourceStruct1_ptr->m1); // flow - sink(sourceStruct1_ptr->getFirst()); // flow [NOT DETECTED with IR] + sink(sourceStruct1_ptr->getFirst()); // flow sink(sourceStruct1_ptr->m2); // no flow sink(sourceStruct1.m1); // no flow diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 10dc6d411b7..2f6b103bc0d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -1,13 +1,6 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation -| dispatch.cpp:60:18:60:29 | call to Bottom | Node should have one location but has 2. | -| dispatch.cpp:61:18:61:29 | call to Middle | Node should have one location but has 2. | -| dispatch.cpp:65:10:65:21 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Middle | Node should have one location but has 2. | missingLocation uniqueNodeToString missingToString @@ -23,9 +16,9 @@ postIsInSameCallable reverseRead storeIsPostUpdate argHasPostUpdate -| dispatch.cpp:78:23:78:39 | * ... | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:32:2:32:2 | c | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. | +| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 3940c1e8389..9b6b19b4957 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | BarrierGuard.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | | acrossLinkTargets.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | @@ -19,9 +18,7 @@ uniqueNodeLocation missingLocation | Nodes without location: 4 | uniqueNodeToString -| lambdas.cpp:2:6:2:9 | (no string representation) | Node should have one toString but has 0. | missingToString -| Nodes without toString: 1 | parameterCallable localFlowIsLocal compatibleTypesReflexive @@ -30,8 +27,6 @@ localCallNodes postIsNotPre postHasUniquePre uniquePostUpdate -| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | -| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead storeIsPostUpdate diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected index 4bd0b9fdc4d..78d20cbf7ae 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected @@ -14,7 +14,9 @@ | example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... | | example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... | | example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords | +| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] | | example.c:26:19:26:24 | coords | example.c:26:18:26:24 | & ... | +| example.c:28:22:28:25 | ref arg & ... | example.c:28:23:28:25 | pos [inner post update] | | example.c:28:23:28:25 | pos | example.c:28:22:28:25 | & ... | | test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 | | test.cpp:6:12:6:17 | call to source | test.cpp:8:8:8:9 | t1 | @@ -44,7 +46,7 @@ | test.cpp:383:12:383:13 | 0 | test.cpp:384:33:384:35 | tmp | | test.cpp:383:12:383:13 | 0 | test.cpp:385:8:385:10 | tmp | | test.cpp:384:10:384:13 | & ... | test.cpp:384:3:384:8 | call to memcpy | -| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:33:384:35 | tmp | +| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:11:384:13 | tmp [inner post update] | | test.cpp:384:10:384:13 | ref arg & ... | test.cpp:385:8:385:10 | tmp | | test.cpp:384:11:384:13 | tmp | test.cpp:384:10:384:13 | & ... | | test.cpp:384:17:384:23 | source1 | test.cpp:384:10:384:13 | ref arg & ... | @@ -58,7 +60,7 @@ | test.cpp:389:12:389:13 | 0 | test.cpp:394:10:394:12 | tmp | | test.cpp:390:19:390:21 | tmp | test.cpp:390:18:390:21 | & ... | | test.cpp:391:10:391:13 | & ... | test.cpp:391:3:391:8 | call to memcpy | -| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:33:391:35 | tmp | +| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:11:391:13 | tmp [inner post update] | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:392:8:392:10 | tmp | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:394:10:394:12 | tmp | | test.cpp:391:11:391:13 | tmp | test.cpp:391:10:391:13 | & ... | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index 666edf7a177..bce01956dc7 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -366,7 +366,7 @@ class FlowThroughFields { } int calledAfterTaint() { - sink(field); // tainted [NOT DETECTED with IR] + sink(field); // tainted } int taintAndCall() { diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index 9bad6e02bcc..d663862361c 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -1,7 +1,6 @@ | BarrierGuard.cpp:49:10:49:15 | BarrierGuard.cpp:51:13:51:13 | AST only | | BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only | | clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only | -| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only | | clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only | @@ -19,11 +18,7 @@ | dispatch.cpp:144:8:144:13 | dispatch.cpp:96:8:96:8 | IR only | | globals.cpp:13:23:13:28 | globals.cpp:12:10:12:24 | IR only | | globals.cpp:23:23:23:28 | globals.cpp:19:10:19:24 | IR only | -| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only | -| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only | -| lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only | -| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only | | lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only | | ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only | | ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only | @@ -39,8 +34,6 @@ | test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only | | test.cpp:347:17:347:22 | test.cpp:349:10:349:18 | AST only | | test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only | -| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only | -| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only | | test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only | | test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only | | test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 35068c56232..f7cedc063ee 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -12,6 +12,7 @@ | clang.cpp:18:8:18:19 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 | | clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 | | clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source | +| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source | | clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source | | clang.cpp:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | call to source | | clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source | @@ -38,7 +39,11 @@ | globals.cpp:6:10:6:14 | local | globals.cpp:5:17:5:22 | call to source | | globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source | | globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source | +| lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source | | ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source | | ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source | | ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source | @@ -65,6 +70,8 @@ | test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source | | test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source | | test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source | +| test.cpp:369:10:369:14 | field | test.cpp:373:13:373:18 | call to source | +| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source | | test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 | | test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 | | test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index fd49e1e85ee..ec0c426faf7 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -40,21 +40,21 @@ public: cc.insert(nullptr); ct.insert(new C()); sink(&cc); // no flow - sink(&ct); // flow + sink(&ct); // $ast $f-:ir } void f1() { C *c = new C(); B *b = B::make(c); - sink(b->c); // flow + sink(b->c); // $ast $f-:ir } void f2() { B *b = new B(); b->set(new C1()); - sink(b->get()); // flow - sink((new B(new C()))->get()); // flow + sink(b->get()); // $ast $ir=55:12 + sink((new B(new C()))->get()); // $ast $ir } void f3() @@ -63,7 +63,7 @@ public: B *b2; b2 = setOnB(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow + sink(b2->c); // $ast $f-:ir } void f4() @@ -72,7 +72,7 @@ public: B *b2; b2 = setOnBWrap(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow + sink(b2->c); // $ast $f-:ir } B *setOnBWrap(B *b1, C *c) @@ -104,7 +104,7 @@ public: { if (C1 *c1 = dynamic_cast(c)) { - sink(c1->a); // flow + sink(c1->a); // $ast $ir } C *cc; if (C2 *c2 = dynamic_cast(c)) @@ -117,7 +117,7 @@ public: } if (C1 *c1 = dynamic_cast(cc)) { - sink(c1->a); // no flow, stopped by cast to C2 [FALSE POSITIVE] + sink(c1->a); //$f+:ast } } @@ -129,7 +129,7 @@ public: { B *b = new B(); f7(b); - sink(b->c); // flow + sink(b->c); // $ast,ir } class D @@ -149,9 +149,9 @@ public: { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // flow x2 - sink(d->b->c); // flow - sink(b->c); // flow + sink(d->b); // $ast,ir=143:25 $ast,ir=150:12 + sink(d->b->c); // $ast $f-:ir + sink(b->c); // $ast,ir } void f10() @@ -162,11 +162,11 @@ public: MyList *l3 = new MyList(nullptr, l2); sink(l3->head); // no flow, b is nested beneath at least one ->next sink(l3->next->head); // no flow - sink(l3->next->next->head); // flow + sink(l3->next->next->head); // $ast $f-:ir sink(l3->next->next->next->head); // no flow for (MyList *l = l3; l != nullptr; l = l->next) { - sink(l->head); // flow + sink(l->head); // $ast $f-:ir } } diff --git a/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll new file mode 100644 index 00000000000..590f8c4415b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll @@ -0,0 +1,32 @@ +private import semmle.code.cpp.dataflow.DataFlow +private import DataFlow + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/B.cpp b/cpp/ql/test/library-tests/dataflow/fields/B.cpp index d1e74175c8d..01a3f0317cc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/B.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/B.cpp @@ -6,7 +6,7 @@ class B Elem *e = new Elem(); Box1 *b1 = new Box1(e, nullptr); Box2 *b2 = new Box2(b1); - sink(b2->box1->elem1); // flow + sink(b2->box1->elem1); // $ast $f-:ir sink(b2->box1->elem2); // no flow } @@ -16,7 +16,7 @@ class B Box1 *b1 = new B::Box1(nullptr, e); Box2 *b2 = new Box2(b1); sink(b2->box1->elem1); // no flow - sink(b2->box1->elem2); // flow + sink(b2->box1->elem2); // $ast $f-:ir } static void sink(void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 7c054279851..892d298a81d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,10 +26,10 @@ public: void func() { - sink(s1); // flow - sink(s2); // flow [NOT DETECTED] - sink(s3); // flow - sink(s4); // flow [NOT DETECTED] + sink(s1); // $ast $ir + sink(s2); // $f-:ast $f-:ir + sink(s3); // $ast $ir + sink(s4); // $f-:ast $f-:ir } static void sink(const void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/D.cpp b/cpp/ql/test/library-tests/dataflow/fields/D.cpp index be77fe3bed9..6ea3114199e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/D.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/D.cpp @@ -19,7 +19,7 @@ public: }; static void sinkWrap(Box2* b2) { - sink(b2->getBox1()->getElem()); + sink(b2->getBox1()->getElem()); // $ast=28:15 $ast=35:15 $ast=42:15 $ast=49:15 $f-:ir } Box2* boxfield; @@ -61,6 +61,6 @@ public: private: void f5b() { - sink(boxfield->box->elem); + sink(boxfield->box->elem); // $ast $f-:ir } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/E.cpp b/cpp/ql/test/library-tests/dataflow/fields/E.cpp index fc745a9facc..03c83f76bed 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/E.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/E.cpp @@ -18,7 +18,7 @@ void sink(char *b); void handlePacket(packet *p) { - sink(p->data.buffer); + sink(p->data.buffer); // $ast $f-:ir } void f(buf* b) @@ -28,7 +28,7 @@ void f(buf* b) argument_source(raw); argument_source(b->buffer); argument_source(p.data.buffer); - sink(raw); - sink(b->buffer); + sink(raw); // $ast $f-:ir + sink(b->buffer); // $ast $f-:ir handlePacket(&p); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll new file mode 100644 index 00000000000..41ddf5a17a8 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll @@ -0,0 +1,32 @@ +private import semmle.code.cpp.ir.dataflow.DataFlow +private import DataFlow + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asConvertedExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll new file mode 100644 index 00000000000..eb6f3247b82 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll @@ -0,0 +1,41 @@ +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST +private import cpp + +private newtype TNode = + TASTNode(AST::DataFlow::Node n) or + TIRNode(IR::DataFlow::Node n) + +class Node extends TNode { + string toString() { none() } + + IR::DataFlow::Node asIR() { none() } + + AST::DataFlow::Node asAST() { none() } + + Location getLocation() { none() } +} + +class ASTNode extends Node, TASTNode { + AST::DataFlow::Node n; + + ASTNode() { this = TASTNode(n) } + + override string toString() { result = n.toString() } + + override AST::DataFlow::Node asAST() { result = n } + + override Location getLocation() { result = n.getLocation() } +} + +class IRNode extends Node, TIRNode { + IR::DataFlow::Node n; + + IRNode() { this = TIRNode(n) } + + override string toString() { result = n.toString() } + + override IR::DataFlow::Node asIR() { result = n } + + override Location getLocation() { result = n.getLocation() } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 8a5dcc0e509..f096692419b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -26,8 +26,8 @@ void callSetters() { referenceSetter(s2); copySetter(s3); - sink(s1.m1); // flow - sink(s2.m1); // flow + sink(s1.m1); // $ast,ir + sink(s2.m1); // $ast,ir sink(s3.m1); // no flow } @@ -35,12 +35,12 @@ void assignAfterAlias() { S s1 = { 0, 0 }; S &ref1 = s1; ref1.m1 = user_input(); - sink(s1.m1); // flow [FALSE NEGATIVE] + sink(s1.m1); // $f-:ast $ir S s2 = { 0, 0 }; S &ref2 = s2; s2.m1 = user_input(); - sink(ref2.m1); // flow [FALSE NEGATIVE] + sink(ref2.m1); // $f-:ast $ir } void assignAfterCopy() { @@ -59,7 +59,7 @@ void assignBeforeCopy() { S s2 = { 0, 0 }; s2.m1 = user_input(); S copy2 = s2; - sink(copy2.m1); // flow + sink(copy2.m1); // $ast,ir } struct Wrapper { @@ -77,18 +77,18 @@ void pointerIntermediate() { Wrapper w = { { 0, 0 } }; S *s = &w.s; s->m1 = user_input(); - sink(w.s.m1); // flow [FALSE NEGATIVE] + sink(w.s.m1); // $f-:ast $ir } void referenceIntermediate() { Wrapper w = { { 0, 0 } }; S &s = w.s; s.m1 = user_input(); - sink(w.s.m1); // flow [FALSE NEGATIVE] + sink(w.s.m1); // $f-:ast $ir } void nestedAssign() { Wrapper w = { { 0, 0 } }; w.s.m1 = user_input(); - sink(w.s.m1); // flow + sink(w.s.m1); // $ast,ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index f0e099a06e6..dbda1502133 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,23 +48,90 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // flow + sink(s.getDirectly()); // $ast $ir } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // flow + sink(s.getIndirectly()); // $ast $ir } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // flow + sink(s.getThroughNonMember()); // $ast $ir } void test_nonMemberSetA() { S s; nonMemberSetA(&s, user_input()); - sink(nonMemberGetA(&s)); // flow + sink(nonMemberGetA(&s)); // $ast,ir +} + +//////////////////// + +struct Inner { + void *a; +}; + +struct Outer { + Inner inner_nested, *inner_ptr; + void *a; +}; + +void taint_inner_a_ptr(Inner *inner) { + inner->a = user_input(); +} + +void taint_inner_a_ref(Inner &inner) { + inner.a = user_input(); +} + +void taint_a_ptr(void **pa) { + *pa = user_input(); +} + +void taint_a_ref(void *&pa) { + pa = user_input(); +} + +void test_outer_with_ptr(Outer *pouter) { + Outer outer; + + taint_inner_a_ptr(&outer.inner_nested); + taint_inner_a_ptr(outer.inner_ptr); + taint_a_ptr(&outer.a); + + taint_inner_a_ptr(&pouter->inner_nested); + taint_inner_a_ptr(pouter->inner_ptr); + taint_a_ptr(&pouter->a); + + sink(outer.inner_nested.a); // $ast,ir + sink(outer.inner_ptr->a); // $ast $f-:ir + sink(outer.a); // $f-:ast $f-:ir + + sink(pouter->inner_nested.a); // $ast,ir + sink(pouter->inner_ptr->a); // $ast $f-:ir + sink(pouter->a); // $f-:ast $f-:ir +} + +void test_outer_with_ref(Outer *pouter) { + Outer outer; + + taint_inner_a_ref(outer.inner_nested); + taint_inner_a_ref(*outer.inner_ptr); + taint_a_ref(outer.a); + + taint_inner_a_ref(pouter->inner_nested); + taint_inner_a_ref(*pouter->inner_ptr); + taint_a_ref(pouter->a); + + sink(outer.inner_nested.a); // $ast,ir + sink(outer.inner_ptr->a); // $ast $f-:ir + sink(outer.a); // $ast $f-:ir + + sink(pouter->inner_nested.a); // $ast,ir + sink(pouter->inner_ptr->a); // $ast $f-:ir + sink(pouter->a); // $ast $f-:ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 31ed50283be..13769912d30 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -22,6 +22,12 @@ public: Bar() : f(0, 0) {} }; +class Outer +{ +public: + Bar inner; +}; + int user_input() { return 42; @@ -31,31 +37,32 @@ void sink(int x) { } -void bar(Bar &b) +void bar(Outer &b) { // The library correctly finds that the four `user_input` sources can make it // to the `sink` calls, but it also finds some source/sink combinations that // are impossible. Those false positives here are a consequence of how the // shared data flow library overapproximates field flow. The library only - // tracks the head (`f`) and the length (2) of the field access path, and - // then it tracks that both `a_` and `b_` have followed `f` in _some_ access - // path somewhere in the search. That makes the library conclude that there - // could be flow to `b.f.a_` even when the flow was actually to `b.f.b_`. - sink(b.f.a()); // flow [FALSE POSITIVE through `b2.f.setB` and `b3.f.setB`] - sink(b.f.b()); // flow [FALSE POSITIVE through `b1.f.setA` and `b3.f.setA`] + // tracks the final two fields (`f` and `inner`) and the length (3) of the field + // access path, and then it tracks that both `a_` and `b_` have followed `f.inner` + // in _some_ access path somewhere in the search. That makes the library conclude + // that there could be flow to `b.inner.f.a_` even when the flow was actually to + // `b.inner.f.b_`. + sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 + sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 } void foo() { - Bar b1; - Bar b2; - Bar b3; - Bar b4; + Outer b1; + Outer b2; + Outer b3; + Outer b4; - b1.f.setA(user_input()); - b2.f.setB(user_input()); - b3.f.setA(user_input()); - b3.f.setB(user_input()); + b1.inner.f.setA(user_input()); + b2.inner.f.setB(user_input()); + b3.inner.f.setA(user_input()); + b3.inner.f.setB(user_input()); // Only a() should alert bar(b1); diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index d9b55c0d4ba..4816180954e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); // flow (through `f` and `h`) - sink(f.b()); // flow (through `g` and `h`) + sink(f.a()); //$ast=34:11 $ast=36:11 $ir=34:11 $ir=36:11 + sink(f.b()); //$ast=35:14 $ast=36:25 $ir=35:14 $ir=36:25 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index cdf03b90508..70d78dfbc89 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -1,31 +1,8 @@ uniqueEnclosingCallable | C.cpp:37:24:37:33 | 0 | Node should have one enclosing callable but has 0. | | C.cpp:37:24:37:33 | new | Node should have one enclosing callable but has 0. | -uniqueTypeBound -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type bound but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type bound but has 0. | -uniqueTypeRepr -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type representation but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type representation but has 0. | +uniqueType uniqueNodeLocation -| A.cpp:38:7:38:8 | call to C | Node should have one location but has 2. | -| A.cpp:39:7:39:8 | call to C | Node should have one location but has 2. | -| A.cpp:41:15:41:21 | call to C | Node should have one location but has 2. | -| A.cpp:47:12:47:18 | call to C | Node should have one location but has 2. | -| A.cpp:57:17:57:23 | call to C | Node should have one location but has 2. | -| A.cpp:64:21:64:28 | call to C2 | Node should have one location but has 2. | -| A.cpp:73:25:73:32 | call to C2 | Node should have one location but has 2. | -| A.cpp:126:12:126:18 | call to C | Node should have one location but has 2. | -| A.cpp:142:14:142:20 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C2 | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C2 | Node should have one location but has 2. | missingLocation uniqueNodeToString missingToString @@ -43,6 +20,7 @@ storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | +| A.cpp:57:11:57:24 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:57:17:57:23 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:64:21:64:28 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:73:25:73:32 | new | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 227023fda16..81d239b8d7c 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,13 +1,13 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation -| D.cpp:1:17:1:17 | o | Node should have one location but has 2. | -| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 2. | +| D.cpp:1:17:1:17 | o | Node should have one location but has 3. | +| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | +| qualifiers.cpp:1:17:1:17 | o | Node should have one location but has 3. | missingLocation | Nodes without location: 4 | uniqueNodeToString diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected new file mode 100644 index 00000000000..9387a511581 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected @@ -0,0 +1,40 @@ +| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | AST only | +| A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | AST only | +| A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | AST only | +| A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | AST only | +| B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | AST only | +| D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | AST only | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | IR only | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | IR only | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | IR only | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | IR only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | AST only | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql new file mode 100644 index 00000000000..47bee0db492 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql @@ -0,0 +1,31 @@ +/** + * @kind problem + */ + +import cpp +import Nodes +import IRConfiguration as IRConf +import ASTConfiguration as ASTConf +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST + +from Node source, Node sink, IRConf::Conf irConf, ASTConf::Conf astConf, string msg +where + irConf.hasFlow(source.asIR(), sink.asIR()) and + not exists(AST::DataFlow::Node astSource, AST::DataFlow::Node astSink | + astSource.asExpr() = source.asIR().asExpr() and + astSink.asExpr() = sink.asIR().asExpr() + | + astConf.hasFlow(astSource, astSink) + ) and + msg = "IR only" + or + astConf.hasFlow(source.asAST(), sink.asAST()) and + not exists(IR::DataFlow::Node irSource, IR::DataFlow::Node irSink | + irSource.asExpr() = source.asAST().asExpr() and + irSink.asExpr() = sink.asAST().asExpr() + | + irConf.hasFlow(irSource, irSink) + ) and + msg = "AST only" +select source, sink, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 650b5dcc073..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -1,598 +0,0 @@ -edges -| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | -| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c | -| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | -| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | -| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | -| A.cpp:55:5:55:5 | b [post update] [c] | A.cpp:56:10:56:10 | b [c] | -| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | b [post update] [c] | -| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | -| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | -| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | -| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] | -| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] | -| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] | -| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c | -| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] | -| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] | -| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c | -| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... | -| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] | -| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] | -| A.cpp:101:8:101:9 | c1 [a] | A.cpp:103:14:103:14 | c [a] | -| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] | -| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | -| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | -| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | -| A.cpp:126:5:126:5 | b [post update] [c] | A.cpp:131:8:131:8 | ref arg b [c] | -| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | b [post update] [c] | -| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | -| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | -| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | -| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] | -| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... | -| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] | -| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] | -| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] | -| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... | -| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | -| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] | -| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] | -| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] | -| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] | -| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b | -| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] | -| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c | -| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c | -| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b | -| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] | -| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | -| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] | -| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] | -| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] | -| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] | -| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head | -| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] | -| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] | -| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] | -| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head | -| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e | -| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] | -| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] | -| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] | -| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | -| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] | -| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 | -| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e | -| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] | -| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] | -| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] | -| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | -| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] | -| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 | -| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] | -| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] | -| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] | -| C.cpp:19:5:19:5 | c [s3] | C.cpp:27:8:27:11 | this [s3] | -| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | C.cpp:18:12:18:18 | call to C [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | -| C.cpp:24:5:24:8 | this [post update] [s3] | C.cpp:18:12:18:18 | call to C [s3] | -| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | this [post update] [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... | -| C.cpp:27:8:27:11 | this [s1] | C.cpp:29:10:29:11 | this [s1] | -| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] | -| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 | -| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] | -| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] | -| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem | -| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... | -| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] | -| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] | -| D.cpp:30:8:30:10 | box [post update] [elem] | D.cpp:30:5:30:5 | b [post update] [box, elem] | -| D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | -| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | -| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | box [post update] [elem] | -| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | -| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | b [post update] [box, elem] | -| D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | D.cpp:51:5:51:5 | b [post update] [box, elem] | -| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | -| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | -| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | -| D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] | -| D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | -| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] | -| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem | -| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] | -| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] | -| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer | -| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | -| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] | -| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] | -| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] | -| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] | -| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] | -| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer | -| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] | -| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | -| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... | -| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | -| aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... | -| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] | -| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] | -| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] | -| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... | -| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] | -| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] | -| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | -| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | -| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | -| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | by_reference.cpp:51:8:51:8 | s [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | s [post update] [a] | -| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | by_reference.cpp:57:8:57:8 | s [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | s [post update] [a] | -| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | by_reference.cpp:63:8:63:8 | s [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | s [post update] [a] | -| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | -| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | -| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | -| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | -| complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | -| complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | -| complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] | -| complex.cpp:44:10:44:10 | f [a_] | complex.cpp:44:12:44:12 | call to a | -| complex.cpp:45:8:45:8 | b [f, b_] | complex.cpp:45:10:45:10 | f [b_] | -| complex.cpp:45:10:45:10 | f [b_] | complex.cpp:45:12:45:12 | call to b | -| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | complex.cpp:61:7:61:8 | b1 [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | -| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | f [post update] [a_] | -| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | complex.cpp:64:7:64:8 | b2 [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | -| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | f [post update] [b_] | -| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | complex.cpp:67:7:67:8 | b3 [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | -| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | f [post update] [a_] | -| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | complex.cpp:67:7:67:8 | b3 [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | -| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | f [post update] [b_] | -| complex.cpp:61:7:61:8 | b1 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | -| complex.cpp:64:7:64:8 | b2 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | -| complex.cpp:67:7:67:8 | b3 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | -| complex.cpp:67:7:67:8 | b3 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | -| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] | -| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] | -| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a | -| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b | -| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] | -| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] | -| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] | -| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] | -| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] | -| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] | -| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] | -| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | -| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | -| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | -| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | -| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | simple.cpp:45:9:45:9 | f [a_] | -| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | f [post update] [a_] | -| simple.cpp:40:5:40:5 | g [post update] [b_] | simple.cpp:48:9:48:9 | g [b_] | -| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | g [post update] [b_] | -| simple.cpp:41:5:41:5 | h [post update] [a_] | simple.cpp:51:9:51:9 | h [a_] | -| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | h [post update] [a_] | -| simple.cpp:42:5:42:5 | h [post update] [b_] | simple.cpp:51:9:51:9 | h [b_] | -| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | h [post update] [b_] | -| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | -| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | -| simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | -| simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] | -| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] | -| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | -| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | -| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | -| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] | -| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a | -| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] | -| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] | -| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] | -| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] | -| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a | -| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] | -| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a | -| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | -| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] | -| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] | -| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] | -| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] | -| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] | -| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] | -| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] | -| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] | -nodes -| A.cpp:41:15:41:21 | new | semmle.label | new | -| A.cpp:43:10:43:12 | & ... | semmle.label | & ... | -| A.cpp:47:12:47:18 | new | semmle.label | new | -| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] | -| A.cpp:48:20:48:20 | c | semmle.label | c | -| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | -| A.cpp:49:13:49:13 | c | semmle.label | c | -| A.cpp:55:5:55:5 | b [post update] [c] | semmle.label | b [post update] [c] | -| A.cpp:55:12:55:19 | new | semmle.label | new | -| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | -| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | -| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] | -| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] | -| A.cpp:57:17:57:23 | new | semmle.label | new | -| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | -| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] | -| A.cpp:64:21:64:28 | new | semmle.label | new | -| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] | -| A.cpp:66:14:66:14 | c | semmle.label | c | -| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] | -| A.cpp:73:25:73:32 | new | semmle.label | new | -| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] | -| A.cpp:75:14:75:14 | c | semmle.label | c | -| A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] | -| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... | -| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] | -| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:107:16:107:16 | a | semmle.label | a | -| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:120:16:120:16 | a | semmle.label | a | -| A.cpp:126:5:126:5 | b [post update] [c] | semmle.label | b [post update] [c] | -| A.cpp:126:12:126:18 | new | semmle.label | new | -| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | -| A.cpp:132:13:132:13 | c | semmle.label | c | -| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] | -| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... | -| A.cpp:142:14:142:20 | new | semmle.label | new | -| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] | -| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] | -| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... | -| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] | -| A.cpp:143:25:143:31 | new | semmle.label | new | -| A.cpp:150:12:150:18 | new | semmle.label | new | -| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] | -| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] | -| A.cpp:151:18:151:18 | b | semmle.label | b | -| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] | -| A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] | -| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] | -| A.cpp:153:16:153:16 | c | semmle.label | c | -| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:159:12:159:18 | new | semmle.label | new | -| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] | -| A.cpp:160:29:160:29 | b | semmle.label | b | -| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] | -| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] | -| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] | -| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] | -| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] | -| A.cpp:165:26:165:29 | head | semmle.label | head | -| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] | -| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] | -| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] | -| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] | -| A.cpp:169:15:169:18 | head | semmle.label | head | -| B.cpp:6:15:6:24 | new | semmle.label | new | -| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] | -| B.cpp:7:25:7:25 | e | semmle.label | e | -| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] | -| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] | -| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] | -| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] | -| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 | -| B.cpp:15:15:15:27 | new | semmle.label | new | -| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] | -| B.cpp:16:37:16:37 | e | semmle.label | e | -| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] | -| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] | -| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] | -| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] | -| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 | -| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] | -| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] | -| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] | -| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] | -| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] | -| C.cpp:22:12:22:21 | new | semmle.label | new | -| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] | -| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... | -| C.cpp:24:16:24:25 | new | semmle.label | new | -| C.cpp:27:8:27:11 | this [s1] | semmle.label | this [s1] | -| C.cpp:27:8:27:11 | this [s3] | semmle.label | this [s3] | -| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] | -| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | -| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] | -| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] | -| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] | -| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] | -| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem | -| D.cpp:28:15:28:24 | new | semmle.label | new | -| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... | -| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:35:15:35:24 | new | semmle.label | new | -| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:37:21:37:21 | e | semmle.label | e | -| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:42:15:42:24 | new | semmle.label | new | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | -| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:49:15:49:24 | new | semmle.label | new | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | -| D.cpp:51:27:51:27 | e | semmle.label | e | -| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:56:15:56:24 | new | semmle.label | new | -| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] | -| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... | -| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] | -| D.cpp:64:25:64:28 | elem | semmle.label | elem | -| E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] | -| E.cpp:21:10:21:10 | p [data, buffer] | semmle.label | p [data, buffer] | -| E.cpp:21:13:21:16 | data [buffer] | semmle.label | data [buffer] | -| E.cpp:21:18:21:23 | buffer | semmle.label | buffer | -| E.cpp:28:21:28:23 | ref arg raw | semmle.label | ref arg raw | -| E.cpp:29:21:29:21 | b [post update] [buffer] | semmle.label | b [post update] [buffer] | -| E.cpp:29:24:29:29 | ref arg buffer | semmle.label | ref arg buffer | -| E.cpp:30:21:30:21 | p [post update] [data, buffer] | semmle.label | p [post update] [data, buffer] | -| E.cpp:30:23:30:26 | data [post update] [buffer] | semmle.label | data [post update] [buffer] | -| E.cpp:30:28:30:33 | ref arg buffer | semmle.label | ref arg buffer | -| E.cpp:31:10:31:12 | raw | semmle.label | raw | -| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] | -| E.cpp:32:13:32:18 | buffer | semmle.label | buffer | -| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] | -| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] | -| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] | -| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] | -| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] | -| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] | -| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] | -| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] | -| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | -| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | semmle.label | s [post update] [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | semmle.label | s [post update] [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | semmle.label | s [post update] [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | -| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | -| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | -| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | -| complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | -| complex.cpp:34:15:34:15 | b [f, b_] | semmle.label | b [f, b_] | -| complex.cpp:44:8:44:8 | b [f, a_] | semmle.label | b [f, a_] | -| complex.cpp:44:10:44:10 | f [a_] | semmle.label | f [a_] | -| complex.cpp:44:12:44:12 | call to a | semmle.label | call to a | -| complex.cpp:45:8:45:8 | b [f, b_] | semmle.label | b [f, b_] | -| complex.cpp:45:10:45:10 | f [b_] | semmle.label | f [b_] | -| complex.cpp:45:12:45:12 | call to b | semmle.label | call to b | -| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | semmle.label | b1 [post update] [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | -| complex.cpp:55:13:55:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | semmle.label | b2 [post update] [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | -| complex.cpp:56:13:56:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | semmle.label | b3 [post update] [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | -| complex.cpp:57:13:57:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | semmle.label | b3 [post update] [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | -| complex.cpp:58:13:58:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:61:7:61:8 | b1 [f, a_] | semmle.label | b1 [f, a_] | -| complex.cpp:64:7:64:8 | b2 [f, b_] | semmle.label | b2 [f, b_] | -| complex.cpp:67:7:67:8 | b3 [f, a_] | semmle.label | b3 [f, a_] | -| complex.cpp:67:7:67:8 | b3 [f, b_] | semmle.label | b3 [f, b_] | -| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | -| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | -| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | -| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] | -| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] | -| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] | -| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | -| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | -| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | -| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | -| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | -| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | -| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | -| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | -| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | semmle.label | f [post update] [a_] | -| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:40:5:40:5 | g [post update] [b_] | semmle.label | g [post update] [b_] | -| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:41:5:41:5 | h [post update] [a_] | semmle.label | h [post update] [a_] | -| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:42:5:42:5 | h [post update] [b_] | semmle.label | h [post update] [b_] | -| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | -| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | -| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] | -| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] | -| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] | -| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... | -| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | -| simple.cpp:67:13:67:13 | i | semmle.label | i | -| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | -| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | -| struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] | -| struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | -| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | -| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | -| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] | -| struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | -| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] | -| struct_init.c:33:25:33:25 | a | semmle.label | a | -| struct_init.c:36:10:36:24 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:36:11:36:15 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | -| struct_init.c:36:17:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | -| struct_init.c:40:17:40:36 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | -| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | -| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] | -#select -| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new | -| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new | -| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | -| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | -| A.cpp:66:14:66:14 | c | A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | c flows from $@ | A.cpp:64:21:64:28 | new | new | -| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new | -| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | -| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | -| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | -| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | -| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | -| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new | -| B.cpp:19:20:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new | -| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | -| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:42:15:42:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:49:15:49:24 | new | new | -| D.cpp:64:25:64:28 | elem | D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | elem flows from $@ | D.cpp:56:15:56:24 | new | new | -| E.cpp:21:18:21:23 | buffer | E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | buffer flows from $@ | E.cpp:30:28:30:33 | ref arg buffer | ref arg buffer | -| E.cpp:31:10:31:12 | raw | E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | raw flows from $@ | E.cpp:28:21:28:23 | ref arg raw | ref arg raw | -| E.cpp:32:13:32:18 | buffer | E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | buffer flows from $@ | E.cpp:29:24:29:29 | ref arg buffer | ref arg buffer | -| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | -| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | -| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | -| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | -| complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | -| complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | -| complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input | -| complex.cpp:45:12:45:12 | call to b | complex.cpp:58:13:58:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:58:13:58:22 | call to user_input | call to user_input | -| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | -| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | -| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | -| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | -| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | -| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | -| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | -| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | -| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | -| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | -| struct_init.c:33:25:33:25 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.ql b/cpp/ql/test/library-tests/dataflow/fields/flow.ql index 816755301db..15cf7ccc0be 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.ql @@ -1,42 +1,34 @@ /** - * @kind path-problem + * @kind problem */ +import TestUtilities.InlineExpectationsTest import semmle.code.cpp.dataflow.DataFlow -import DataFlow::PathGraph -import DataFlow +import ASTConfiguration import cpp -class Conf extends Configuration { - Conf() { this = "FieldFlowConf" } +class ASTFieldFlowTest extends InlineExpectationsTest { + ASTFieldFlowTest() { this = "ASTFieldFlowTest" } - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") + override string getARelevantTag() { result = "ast" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n | + tag = "ast" and + conf.hasFlow(source, sink) and + n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and + ( + n = 1 and value = "" + or + // If there is more than one source for this sink + // we specify the source location explicitly. + n > 1 and + value = + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartColumn() + ) and + location = sink.getLocation() and + element = sink.toString() ) } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } } - -from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf -where conf.hasFlowPath(src, sink) -select sink, src, sink, sink + " flows from $@", src, src.toString() diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 4286d556cb9..d24c311a65b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -1,90 +1,4 @@ -edges -| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | -| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | -| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | -| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | -| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | -| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | -| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | -| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | -| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | -| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | -| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -nodes -| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:142:7:142:20 | Store | semmle.label | Store | -| A.cpp:142:14:142:20 | new | semmle.label | new | -| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | -| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | -| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | -| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | -| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | -| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | -| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | -| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | -| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | -| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | -| simple.cpp:67:13:67:13 | i | semmle.label | i | -| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | -| struct_init.c:31:23:31:23 | a | semmle.label | a | -#select -| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | -| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | -| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | -| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | -| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | -| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | -| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | -| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | -| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=63:19 | +| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=65:19 | +| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=62:19 | +| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=64:19 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql index 098c6b6bd27..75ee23e6520 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -1,46 +1,34 @@ /** - * @kind path-problem + * @kind problem */ +import TestUtilities.InlineExpectationsTest import semmle.code.cpp.ir.dataflow.DataFlow -import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate -import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil -import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl -import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon -import semmle.code.cpp.ir.IR -import DataFlow::PathGraph +import IRConfiguration import cpp -class Conf extends DataFlow::Configuration { - Conf() { this = "FieldFlowConf" } +class IRFieldFlowTest extends InlineExpectationsTest { + IRFieldFlowTest() { this = "IRFieldFlowTest" } - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") + override string getARelevantTag() { result = "ir" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n | + tag = "ir" and + conf.hasFlow(source, sink) and + n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and + ( + n = 1 and value = "" + or + // If there is more than one source for this sink + // we specify the source location explicitly. + n > 1 and + value = + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartColumn() + ) and + location = sink.getLocation() and + element = sink.toString() ) } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } } - -from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf -where conf.hasFlowPath(src, sink) -select sink, src, sink, sink + " flows from $@", src, src.toString() diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected new file mode 100644 index 00000000000..2a4ccb44908 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -0,0 +1,413 @@ +edges +| A.cpp:55:5:55:5 | set output argument [c] | A.cpp:56:10:56:10 | Argument -1 indirection [c] | +| A.cpp:55:12:55:19 | (C *)... | A.cpp:55:5:55:5 | set output argument [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:12:55:19 | (C *)... | +| A.cpp:56:10:56:10 | Argument -1 indirection [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | +| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | +| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | +| A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | +| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | +| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | +| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | +| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | +| C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | +| C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | +| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | +| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | +| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | +| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | +| by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | +| by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | +| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:18:51:18 | call to a | +| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | complex.cpp:51:16:51:16 | a output argument [b_] | +| complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | +| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | complex.cpp:52:18:52:18 | call to b | +| complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | setA output argument [a_] | +| complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | setB output argument [b_] | +| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | +| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | setA output argument [a_] | +| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | complex.cpp:65:12:65:12 | setB output argument [a_] | +| complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | +| complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | setB output argument [b_] | +| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | constructors.cpp:28:12:28:12 | call to a | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | +| constructors.cpp:28:10:28:10 | a output argument [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | Foo output argument [a_] | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | Foo output argument [b_] | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [b_] | +| constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:26:15:26:15 | *f [a_] | simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | simple.cpp:28:12:28:12 | call to a | +| simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | simple.cpp:28:10:28:10 | a output argument [b_] | +| simple.cpp:28:10:28:10 | a output argument [b_] | simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | setA output argument [a_] | +| simple.cpp:40:5:40:5 | setB output argument [b_] | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | setB output argument [b_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | setA output argument [a_] | +| simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | simple.cpp:42:5:42:5 | setB output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | +| simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | +| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | +| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | +| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | +| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | +| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | +nodes +| A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | +| A.cpp:55:12:55:19 | new | semmle.label | new | +| A.cpp:56:10:56:10 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:57:10:57:25 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | +| A.cpp:57:11:57:24 | B output argument [c] | semmle.label | B output argument [c] | +| A.cpp:57:17:57:23 | new | semmle.label | new | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | +| A.cpp:98:12:98:18 | new | semmle.label | new | +| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | +| A.cpp:100:5:100:13 | Store | semmle.label | Store | +| A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +| A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | +| A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | +| A.cpp:132:13:132:13 | c | semmle.label | c | +| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:143:7:143:31 | Store | semmle.label | Store | +| A.cpp:143:25:143:31 | new | semmle.label | new | +| A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | +| A.cpp:151:18:151:18 | b | semmle.label | b | +| A.cpp:152:13:152:13 | b | semmle.label | b | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:12:22:21 | Store | semmle.label | Store | +| C.cpp:22:12:22:21 | new | semmle.label | new | +| C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | +| C.cpp:24:5:24:25 | Store | semmle.label | Store | +| C.cpp:24:16:24:25 | new | semmle.label | new | +| C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | +| C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | +| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | +| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | semmle.label | setIndirectly output argument [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | semmle.label | setThroughNonMember output argument [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | +| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | +| complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| complex.cpp:51:16:51:16 | a output argument [b_] | semmle.label | a output argument [b_] | +| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | +| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | +| complex.cpp:62:12:62:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:63:12:63:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:64:12:64:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| complex.cpp:65:12:65:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| complex.cpp:65:12:65:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| constructors.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| simple.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| simple.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| simple.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:40:5:40:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:41:5:41:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| simple.cpp:83:9:83:28 | Store | semmle.label | Store | +| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | +| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | +| struct_init.c:15:12:15:12 | a | semmle.label | a | +| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:20:20:20:29 | Store | semmle.label | Store | +| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:22:11:22:11 | a | semmle.label | a | +| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:27:7:27:16 | Store | semmle.label | Store | +| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:31:23:31:23 | a | semmle.label | a | +| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +#select +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | +| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | +| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql new file mode 100644 index 00000000000..eadcbab4bbc --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import semmle.code.cpp.ir.dataflow.DataFlow +import IRConfiguration +import cpp +import DataFlow::PathGraph + +from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(src, sink) +select sink, src, sink, sink + " flows from $@", src, src.toString() diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected new file mode 100644 index 00000000000..889f789da8d --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -0,0 +1,347 @@ +| A.cpp:25:13:25:13 | c | AST only | +| A.cpp:27:28:27:28 | c | AST only | +| A.cpp:31:20:31:20 | c | AST only | +| A.cpp:40:5:40:6 | cc | AST only | +| A.cpp:41:5:41:6 | ct | AST only | +| A.cpp:42:10:42:12 | & ... | AST only | +| A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:48:20:48:20 | c | AST only | +| A.cpp:49:10:49:10 | b | AST only | +| A.cpp:49:13:49:13 | c | AST only | +| A.cpp:55:5:55:5 | b | AST only | +| A.cpp:56:10:56:10 | b | AST only | +| A.cpp:56:13:56:15 | call to get | AST only | +| A.cpp:57:28:57:30 | call to get | AST only | +| A.cpp:64:10:64:15 | this | AST only | +| A.cpp:64:17:64:18 | b1 | AST only | +| A.cpp:65:10:65:11 | b1 | AST only | +| A.cpp:65:14:65:14 | c | AST only | +| A.cpp:66:10:66:11 | b2 | AST only | +| A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:10:73:19 | this | AST only | +| A.cpp:73:21:73:22 | b1 | AST only | +| A.cpp:74:10:74:11 | b1 | AST only | +| A.cpp:74:14:74:14 | c | AST only | +| A.cpp:75:10:75:11 | b2 | AST only | +| A.cpp:75:14:75:14 | c | AST only | +| A.cpp:81:10:81:15 | this | AST only | +| A.cpp:81:17:81:18 | b1 | AST only | +| A.cpp:81:21:81:21 | c | AST only | +| A.cpp:82:12:82:12 | this | AST only | +| A.cpp:87:9:87:9 | this | AST only | +| A.cpp:90:7:90:8 | b2 | AST only | +| A.cpp:90:15:90:15 | c | AST only | +| A.cpp:100:9:100:9 | a | AST only | +| A.cpp:101:5:101:6 | this | AST only | +| A.cpp:101:8:101:9 | c1 | AST only | +| A.cpp:107:12:107:13 | c1 | AST only | +| A.cpp:107:16:107:16 | a | AST only | +| A.cpp:120:12:120:13 | c1 | AST only | +| A.cpp:120:16:120:16 | a | AST only | +| A.cpp:126:5:126:5 | b | AST only | +| A.cpp:131:5:131:6 | this | AST only | +| A.cpp:131:8:131:8 | b | AST only | +| A.cpp:132:10:132:10 | b | AST only | +| A.cpp:132:13:132:13 | c | AST only | +| A.cpp:142:10:142:10 | c | AST only | +| A.cpp:143:13:143:13 | b | AST only | +| A.cpp:151:18:151:18 | b | AST only | +| A.cpp:151:21:151:21 | this | AST only | +| A.cpp:152:10:152:10 | d | AST only | +| A.cpp:152:13:152:13 | b | AST only | +| A.cpp:153:10:153:10 | d | AST only | +| A.cpp:153:13:153:13 | b | AST only | +| A.cpp:153:16:153:16 | c | AST only | +| A.cpp:154:10:154:10 | b | AST only | +| A.cpp:154:13:154:13 | c | AST only | +| A.cpp:160:29:160:29 | b | AST only | +| A.cpp:161:38:161:39 | l1 | AST only | +| A.cpp:162:38:162:39 | l2 | AST only | +| A.cpp:163:10:163:11 | l3 | AST only | +| A.cpp:163:14:163:17 | head | AST only | +| A.cpp:164:10:164:11 | l3 | AST only | +| A.cpp:164:14:164:17 | next | AST only | +| A.cpp:164:20:164:23 | head | AST only | +| A.cpp:165:10:165:11 | l3 | AST only | +| A.cpp:165:14:165:17 | next | AST only | +| A.cpp:165:20:165:23 | next | AST only | +| A.cpp:165:26:165:29 | head | AST only | +| A.cpp:166:10:166:11 | l3 | AST only | +| A.cpp:166:14:166:17 | next | AST only | +| A.cpp:166:20:166:23 | next | AST only | +| A.cpp:166:26:166:29 | next | AST only | +| A.cpp:166:32:166:35 | head | AST only | +| A.cpp:169:12:169:12 | l | AST only | +| A.cpp:169:15:169:18 | head | AST only | +| A.cpp:183:7:183:10 | head | AST only | +| A.cpp:184:13:184:16 | next | AST only | +| B.cpp:7:25:7:25 | e | AST only | +| B.cpp:8:25:8:26 | b1 | AST only | +| B.cpp:9:10:9:11 | b2 | AST only | +| B.cpp:9:14:9:17 | box1 | AST only | +| B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:10:10:10:11 | b2 | AST only | +| B.cpp:10:14:10:17 | box1 | AST only | +| B.cpp:10:20:10:24 | elem2 | AST only | +| B.cpp:16:37:16:37 | e | AST only | +| B.cpp:17:25:17:26 | b1 | AST only | +| B.cpp:18:10:18:11 | b2 | AST only | +| B.cpp:18:14:18:17 | box1 | AST only | +| B.cpp:18:20:18:24 | elem1 | AST only | +| B.cpp:19:10:19:11 | b2 | AST only | +| B.cpp:19:14:19:17 | box1 | AST only | +| B.cpp:19:20:19:24 | elem2 | AST only | +| B.cpp:35:13:35:17 | elem1 | AST only | +| B.cpp:36:13:36:17 | elem2 | AST only | +| B.cpp:46:13:46:16 | box1 | AST only | +| C.cpp:19:5:19:5 | c | AST only | +| C.cpp:24:11:24:12 | s3 | AST only | +| D.cpp:9:21:9:24 | elem | AST only | +| D.cpp:11:29:11:32 | elem | AST only | +| D.cpp:16:21:16:23 | box | AST only | +| D.cpp:18:29:18:31 | box | AST only | +| D.cpp:22:10:22:11 | b2 | AST only | +| D.cpp:22:14:22:20 | call to getBox1 | AST only | +| D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:30:5:30:5 | b | AST only | +| D.cpp:30:8:30:10 | box | AST only | +| D.cpp:30:13:30:16 | elem | AST only | +| D.cpp:31:14:31:14 | b | AST only | +| D.cpp:37:5:37:5 | b | AST only | +| D.cpp:37:8:37:10 | box | AST only | +| D.cpp:37:21:37:21 | e | AST only | +| D.cpp:38:14:38:14 | b | AST only | +| D.cpp:44:5:44:5 | b | AST only | +| D.cpp:44:8:44:14 | call to getBox1 | AST only | +| D.cpp:44:19:44:22 | elem | AST only | +| D.cpp:45:14:45:14 | b | AST only | +| D.cpp:51:5:51:5 | b | AST only | +| D.cpp:51:8:51:14 | call to getBox1 | AST only | +| D.cpp:51:27:51:27 | e | AST only | +| D.cpp:52:14:52:14 | b | AST only | +| D.cpp:57:5:57:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | this | AST only | +| D.cpp:58:15:58:17 | box | AST only | +| D.cpp:58:20:58:23 | elem | AST only | +| D.cpp:59:5:59:7 | this | AST only | +| D.cpp:64:10:64:17 | boxfield | AST only | +| D.cpp:64:10:64:17 | this | AST only | +| D.cpp:64:20:64:22 | box | AST only | +| D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:21:10:21:10 | p | AST only | +| E.cpp:21:13:21:16 | data | AST only | +| E.cpp:21:18:21:23 | buffer | AST only | +| E.cpp:28:21:28:23 | raw | AST only | +| E.cpp:29:21:29:21 | b | AST only | +| E.cpp:29:24:29:29 | buffer | AST only | +| E.cpp:30:21:30:21 | p | AST only | +| E.cpp:30:23:30:26 | data | AST only | +| E.cpp:30:28:30:33 | buffer | AST only | +| E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:32:10:32:10 | b | AST only | +| E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:33:18:33:19 | & ... | AST only | +| aliasing.cpp:9:6:9:7 | m1 | AST only | +| aliasing.cpp:13:5:13:6 | m1 | AST only | +| aliasing.cpp:17:5:17:6 | m1 | AST only | +| aliasing.cpp:25:17:25:19 | & ... | AST only | +| aliasing.cpp:26:19:26:20 | s2 | AST only | +| aliasing.cpp:37:8:37:9 | m1 | AST only | +| aliasing.cpp:42:6:42:7 | m1 | AST only | +| aliasing.cpp:49:9:49:10 | m1 | AST only | +| aliasing.cpp:54:6:54:7 | m1 | AST only | +| aliasing.cpp:60:6:60:7 | m1 | AST only | +| aliasing.cpp:72:5:72:6 | m1 | AST only | +| aliasing.cpp:79:6:79:7 | m1 | AST only | +| aliasing.cpp:86:5:86:6 | m1 | AST only | +| aliasing.cpp:92:3:92:3 | w | AST only | +| aliasing.cpp:92:7:92:8 | m1 | AST only | +| by_reference.cpp:12:8:12:8 | a | AST only | +| by_reference.cpp:16:11:16:11 | a | AST only | +| by_reference.cpp:20:5:20:8 | this | AST only | +| by_reference.cpp:20:23:20:27 | value | AST only | +| by_reference.cpp:24:19:24:22 | this | AST only | +| by_reference.cpp:24:25:24:29 | value | AST only | +| by_reference.cpp:50:3:50:3 | s | AST only | +| by_reference.cpp:50:17:50:26 | call to user_input | AST only | +| by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | +| by_reference.cpp:56:3:56:3 | s | AST only | +| by_reference.cpp:56:19:56:28 | call to user_input | AST only | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | AST only | +| by_reference.cpp:62:3:62:3 | s | AST only | +| by_reference.cpp:62:25:62:34 | call to user_input | AST only | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | AST only | +| by_reference.cpp:68:17:68:18 | & ... | AST only | +| by_reference.cpp:68:21:68:30 | call to user_input | AST only | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only | +| by_reference.cpp:84:10:84:10 | a | AST only | +| by_reference.cpp:88:9:88:9 | a | AST only | +| by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:102:22:102:26 | outer | AST only | +| by_reference.cpp:103:21:103:25 | outer | AST only | +| by_reference.cpp:103:27:103:35 | inner_ptr | AST only | +| by_reference.cpp:104:15:104:22 | & ... | AST only | +| by_reference.cpp:104:16:104:20 | outer | AST only | +| by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:106:22:106:27 | pouter | AST only | +| by_reference.cpp:107:21:107:26 | pouter | AST only | +| by_reference.cpp:107:29:107:37 | inner_ptr | AST only | +| by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:108:16:108:21 | pouter | AST only | +| by_reference.cpp:110:8:110:12 | outer | AST only | +| by_reference.cpp:110:14:110:25 | inner_nested | AST only | +| by_reference.cpp:110:27:110:27 | a | AST only | +| by_reference.cpp:111:8:111:12 | outer | AST only | +| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | +| by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:112:8:112:12 | outer | AST only | +| by_reference.cpp:112:14:112:14 | a | AST only | +| by_reference.cpp:114:8:114:13 | pouter | AST only | +| by_reference.cpp:114:16:114:27 | inner_nested | AST only | +| by_reference.cpp:114:29:114:29 | a | AST only | +| by_reference.cpp:115:8:115:13 | pouter | AST only | +| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | +| by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:116:8:116:13 | pouter | AST only | +| by_reference.cpp:116:16:116:16 | a | AST only | +| by_reference.cpp:122:21:122:25 | outer | AST only | +| by_reference.cpp:122:27:122:38 | inner_nested | AST only | +| by_reference.cpp:123:21:123:36 | * ... | AST only | +| by_reference.cpp:123:22:123:26 | outer | AST only | +| by_reference.cpp:124:15:124:19 | outer | AST only | +| by_reference.cpp:124:21:124:21 | a | AST only | +| by_reference.cpp:126:21:126:26 | pouter | AST only | +| by_reference.cpp:126:29:126:40 | inner_nested | AST only | +| by_reference.cpp:127:21:127:38 | * ... | AST only | +| by_reference.cpp:127:22:127:27 | pouter | AST only | +| by_reference.cpp:128:15:128:20 | pouter | AST only | +| by_reference.cpp:128:23:128:23 | a | AST only | +| by_reference.cpp:130:8:130:12 | outer | AST only | +| by_reference.cpp:130:14:130:25 | inner_nested | AST only | +| by_reference.cpp:130:27:130:27 | a | AST only | +| by_reference.cpp:131:8:131:12 | outer | AST only | +| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | +| by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:132:8:132:12 | outer | AST only | +| by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:134:8:134:13 | pouter | AST only | +| by_reference.cpp:134:16:134:27 | inner_nested | AST only | +| by_reference.cpp:134:29:134:29 | a | AST only | +| by_reference.cpp:135:8:135:13 | pouter | AST only | +| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | +| by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:136:8:136:13 | pouter | AST only | +| by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:11:22:11:23 | a_ | AST only | +| complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:51:8:51:8 | b | AST only | +| complex.cpp:51:10:51:14 | inner | AST only | +| complex.cpp:51:16:51:16 | f | AST only | +| complex.cpp:52:8:52:8 | b | AST only | +| complex.cpp:52:10:52:14 | inner | AST only | +| complex.cpp:52:16:52:16 | f | AST only | +| complex.cpp:62:3:62:4 | b1 | AST only | +| complex.cpp:62:6:62:10 | inner | AST only | +| complex.cpp:62:12:62:12 | f | AST only | +| complex.cpp:63:3:63:4 | b2 | AST only | +| complex.cpp:63:6:63:10 | inner | AST only | +| complex.cpp:63:12:63:12 | f | AST only | +| complex.cpp:64:3:64:4 | b3 | AST only | +| complex.cpp:64:6:64:10 | inner | AST only | +| complex.cpp:64:12:64:12 | f | AST only | +| complex.cpp:65:3:65:4 | b3 | AST only | +| complex.cpp:65:6:65:10 | inner | AST only | +| complex.cpp:65:12:65:12 | f | AST only | +| complex.cpp:68:7:68:8 | b1 | AST only | +| complex.cpp:71:7:71:8 | b2 | AST only | +| complex.cpp:74:7:74:8 | b3 | AST only | +| complex.cpp:77:7:77:8 | b4 | AST only | +| constructors.cpp:20:24:20:25 | a_ | AST only | +| constructors.cpp:21:24:21:25 | b_ | AST only | +| constructors.cpp:28:10:28:10 | f | AST only | +| constructors.cpp:29:10:29:10 | f | AST only | +| constructors.cpp:40:9:40:9 | f | AST only | +| constructors.cpp:43:9:43:9 | g | AST only | +| constructors.cpp:46:9:46:9 | h | AST only | +| constructors.cpp:49:9:49:9 | i | AST only | +| qualifiers.cpp:9:36:9:36 | a | AST only | +| qualifiers.cpp:12:56:12:56 | a | AST only | +| qualifiers.cpp:13:57:13:57 | a | AST only | +| qualifiers.cpp:22:5:22:9 | outer | AST only | +| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | +| qualifiers.cpp:22:23:22:23 | a | AST only | +| qualifiers.cpp:23:10:23:14 | outer | AST only | +| qualifiers.cpp:23:16:23:20 | inner | AST only | +| qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:5:27:9 | outer | AST only | +| qualifiers.cpp:27:11:27:18 | call to getInner | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | AST only | +| qualifiers.cpp:28:10:28:14 | outer | AST only | +| qualifiers.cpp:28:16:28:20 | inner | AST only | +| qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:17:32:21 | outer | AST only | +| qualifiers.cpp:32:23:32:30 | call to getInner | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | AST only | +| qualifiers.cpp:33:10:33:14 | outer | AST only | +| qualifiers.cpp:33:16:33:20 | inner | AST only | +| qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:19:37:35 | * ... | AST only | +| qualifiers.cpp:37:20:37:24 | outer | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | AST only | +| qualifiers.cpp:38:10:38:14 | outer | AST only | +| qualifiers.cpp:38:16:38:20 | inner | AST only | +| qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:6:42:22 | * ... | AST only | +| qualifiers.cpp:42:7:42:11 | outer | AST only | +| qualifiers.cpp:42:25:42:25 | a | AST only | +| qualifiers.cpp:43:10:43:14 | outer | AST only | +| qualifiers.cpp:43:16:43:20 | inner | AST only | +| qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:6:47:11 | & ... | AST only | +| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | +| qualifiers.cpp:47:27:47:27 | a | AST only | +| qualifiers.cpp:48:10:48:14 | outer | AST only | +| qualifiers.cpp:48:16:48:20 | inner | AST only | +| qualifiers.cpp:48:23:48:23 | a | AST only | +| simple.cpp:20:24:20:25 | a_ | AST only | +| simple.cpp:21:24:21:25 | b_ | AST only | +| simple.cpp:28:10:28:10 | f | AST only | +| simple.cpp:29:10:29:10 | f | AST only | +| simple.cpp:39:5:39:5 | f | AST only | +| simple.cpp:40:5:40:5 | g | AST only | +| simple.cpp:41:5:41:5 | h | AST only | +| simple.cpp:42:5:42:5 | h | AST only | +| simple.cpp:45:9:45:9 | f | AST only | +| simple.cpp:48:9:48:9 | g | AST only | +| simple.cpp:51:9:51:9 | h | AST only | +| simple.cpp:54:9:54:9 | i | AST only | +| simple.cpp:65:7:65:7 | i | AST only | +| simple.cpp:83:9:83:10 | this | AST only | +| simple.cpp:83:12:83:13 | f1 | AST only | +| simple.cpp:84:14:84:20 | this | AST only | +| struct_init.c:15:8:15:9 | ab | AST only | +| struct_init.c:15:12:15:12 | a | AST only | +| struct_init.c:16:8:16:9 | ab | AST only | +| struct_init.c:16:12:16:12 | b | AST only | +| struct_init.c:22:8:22:9 | ab | AST only | +| struct_init.c:22:11:22:11 | a | AST only | +| struct_init.c:23:8:23:9 | ab | AST only | +| struct_init.c:23:11:23:11 | b | AST only | +| struct_init.c:24:10:24:12 | & ... | AST only | +| struct_init.c:31:8:31:12 | outer | AST only | +| struct_init.c:31:14:31:21 | nestedAB | AST only | +| struct_init.c:31:23:31:23 | a | AST only | +| struct_init.c:32:8:32:12 | outer | AST only | +| struct_init.c:32:14:32:21 | nestedAB | AST only | +| struct_init.c:32:23:32:23 | b | AST only | +| struct_init.c:33:8:33:12 | outer | AST only | +| struct_init.c:33:14:33:22 | pointerAB | AST only | +| struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:34:8:34:12 | outer | AST only | +| struct_init.c:34:14:34:22 | pointerAB | AST only | +| struct_init.c:34:25:34:25 | b | AST only | +| struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:36:11:36:15 | outer | AST only | +| struct_init.c:46:10:46:14 | outer | AST only | +| struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql new file mode 100644 index 00000000000..d8b6b4e0e69 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -0,0 +1,33 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IR +import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST +import Nodes + +class ASTPartialDefNode extends ASTNode { + ASTPartialDefNode() { exists(n.asPartialDefinition()) } + + override string toString() { result = n.asPartialDefinition().toString() } +} + +class IRPartialDefNode extends IRNode { + IRPartialDefNode() { exists(n.asPartialDefinition()) } + + override string toString() { result = n.asPartialDefinition().toString() } +} + +from Node node, AST::Node astNode, IR::Node irNode, string msg +where + node.asIR() = irNode and + exists(irNode.asPartialDefinition()) and + not exists(AST::Node otherNode | otherNode.asPartialDefinition() = irNode.asPartialDefinition()) and + msg = "IR only" + or + node.asAST() = astNode and + exists(astNode.asPartialDefinition()) and + not exists(IR::Node otherNode | otherNode.asPartialDefinition() = astNode.asPartialDefinition()) and + msg = "AST only" +select node, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected new file mode 100644 index 00000000000..050f4bc47d5 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -0,0 +1,43 @@ +| A.cpp:25:7:25:10 | this | +| A.cpp:27:22:27:25 | this | +| A.cpp:100:5:100:6 | c1 | +| A.cpp:142:7:142:7 | b | +| A.cpp:143:7:143:10 | this | +| A.cpp:183:7:183:10 | this | +| A.cpp:184:7:184:10 | this | +| B.cpp:35:7:35:10 | this | +| B.cpp:36:7:36:10 | this | +| B.cpp:46:7:46:10 | this | +| C.cpp:24:5:24:8 | this | +| D.cpp:9:21:9:24 | this | +| D.cpp:11:29:11:32 | this | +| D.cpp:16:21:16:23 | this | +| D.cpp:18:29:18:31 | this | +| D.cpp:57:5:57:12 | this | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:92:5:92:5 | s | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:16:5:16:8 | this | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:88:3:88:7 | inner | +| complex.cpp:11:22:11:23 | this | +| complex.cpp:12:22:12:23 | this | +| constructors.cpp:20:24:20:25 | this | +| constructors.cpp:21:24:21:25 | this | +| qualifiers.cpp:9:30:9:33 | this | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:13:51:13:55 | inner | +| simple.cpp:20:24:20:25 | this | +| simple.cpp:21:24:21:25 | this | +| simple.cpp:65:5:65:5 | a | +| simple.cpp:83:9:83:10 | f2 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql new file mode 100644 index 00000000000..0f0d3c41b88 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected new file mode 100644 index 00000000000..3f5a2e497d8 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -0,0 +1,390 @@ +| A.cpp:25:7:25:10 | this | +| A.cpp:25:13:25:13 | c | +| A.cpp:27:22:27:25 | this | +| A.cpp:27:28:27:28 | c | +| A.cpp:31:20:31:20 | c | +| A.cpp:40:5:40:6 | cc | +| A.cpp:41:5:41:6 | ct | +| A.cpp:42:10:42:12 | & ... | +| A.cpp:43:10:43:12 | & ... | +| A.cpp:48:20:48:20 | c | +| A.cpp:49:10:49:10 | b | +| A.cpp:49:13:49:13 | c | +| A.cpp:55:5:55:5 | b | +| A.cpp:56:10:56:10 | b | +| A.cpp:56:13:56:15 | call to get | +| A.cpp:57:28:57:30 | call to get | +| A.cpp:64:10:64:15 | this | +| A.cpp:64:17:64:18 | b1 | +| A.cpp:65:10:65:11 | b1 | +| A.cpp:65:14:65:14 | c | +| A.cpp:66:10:66:11 | b2 | +| A.cpp:66:14:66:14 | c | +| A.cpp:73:10:73:19 | this | +| A.cpp:73:21:73:22 | b1 | +| A.cpp:74:10:74:11 | b1 | +| A.cpp:74:14:74:14 | c | +| A.cpp:75:10:75:11 | b2 | +| A.cpp:75:14:75:14 | c | +| A.cpp:81:10:81:15 | this | +| A.cpp:81:17:81:18 | b1 | +| A.cpp:81:21:81:21 | c | +| A.cpp:82:12:82:12 | this | +| A.cpp:87:9:87:9 | this | +| A.cpp:90:7:90:8 | b2 | +| A.cpp:90:15:90:15 | c | +| A.cpp:100:5:100:6 | c1 | +| A.cpp:100:9:100:9 | a | +| A.cpp:101:5:101:6 | this | +| A.cpp:101:8:101:9 | c1 | +| A.cpp:107:12:107:13 | c1 | +| A.cpp:107:16:107:16 | a | +| A.cpp:120:12:120:13 | c1 | +| A.cpp:120:16:120:16 | a | +| A.cpp:126:5:126:5 | b | +| A.cpp:131:5:131:6 | this | +| A.cpp:131:8:131:8 | b | +| A.cpp:132:10:132:10 | b | +| A.cpp:132:13:132:13 | c | +| A.cpp:142:7:142:7 | b | +| A.cpp:142:10:142:10 | c | +| A.cpp:143:7:143:10 | this | +| A.cpp:143:13:143:13 | b | +| A.cpp:151:18:151:18 | b | +| A.cpp:151:21:151:21 | this | +| A.cpp:152:10:152:10 | d | +| A.cpp:152:13:152:13 | b | +| A.cpp:153:10:153:10 | d | +| A.cpp:153:13:153:13 | b | +| A.cpp:153:16:153:16 | c | +| A.cpp:154:10:154:10 | b | +| A.cpp:154:13:154:13 | c | +| A.cpp:160:29:160:29 | b | +| A.cpp:161:38:161:39 | l1 | +| A.cpp:162:38:162:39 | l2 | +| A.cpp:163:10:163:11 | l3 | +| A.cpp:163:14:163:17 | head | +| A.cpp:164:10:164:11 | l3 | +| A.cpp:164:14:164:17 | next | +| A.cpp:164:20:164:23 | head | +| A.cpp:165:10:165:11 | l3 | +| A.cpp:165:14:165:17 | next | +| A.cpp:165:20:165:23 | next | +| A.cpp:165:26:165:29 | head | +| A.cpp:166:10:166:11 | l3 | +| A.cpp:166:14:166:17 | next | +| A.cpp:166:20:166:23 | next | +| A.cpp:166:26:166:29 | next | +| A.cpp:166:32:166:35 | head | +| A.cpp:169:12:169:12 | l | +| A.cpp:169:15:169:18 | head | +| A.cpp:183:7:183:10 | head | +| A.cpp:183:7:183:10 | this | +| A.cpp:184:7:184:10 | this | +| A.cpp:184:13:184:16 | next | +| B.cpp:7:25:7:25 | e | +| B.cpp:8:25:8:26 | b1 | +| B.cpp:9:10:9:11 | b2 | +| B.cpp:9:14:9:17 | box1 | +| B.cpp:9:20:9:24 | elem1 | +| B.cpp:10:10:10:11 | b2 | +| B.cpp:10:14:10:17 | box1 | +| B.cpp:10:20:10:24 | elem2 | +| B.cpp:16:37:16:37 | e | +| B.cpp:17:25:17:26 | b1 | +| B.cpp:18:10:18:11 | b2 | +| B.cpp:18:14:18:17 | box1 | +| B.cpp:18:20:18:24 | elem1 | +| B.cpp:19:10:19:11 | b2 | +| B.cpp:19:14:19:17 | box1 | +| B.cpp:19:20:19:24 | elem2 | +| B.cpp:35:7:35:10 | this | +| B.cpp:35:13:35:17 | elem1 | +| B.cpp:36:7:36:10 | this | +| B.cpp:36:13:36:17 | elem2 | +| B.cpp:46:7:46:10 | this | +| B.cpp:46:13:46:16 | box1 | +| C.cpp:19:5:19:5 | c | +| C.cpp:24:5:24:8 | this | +| C.cpp:24:11:24:12 | s3 | +| D.cpp:9:21:9:24 | elem | +| D.cpp:9:21:9:24 | this | +| D.cpp:11:29:11:32 | elem | +| D.cpp:11:29:11:32 | this | +| D.cpp:16:21:16:23 | box | +| D.cpp:16:21:16:23 | this | +| D.cpp:18:29:18:31 | box | +| D.cpp:18:29:18:31 | this | +| D.cpp:22:10:22:11 | b2 | +| D.cpp:22:14:22:20 | call to getBox1 | +| D.cpp:22:25:22:31 | call to getElem | +| D.cpp:30:5:30:5 | b | +| D.cpp:30:8:30:10 | box | +| D.cpp:30:13:30:16 | elem | +| D.cpp:31:14:31:14 | b | +| D.cpp:37:5:37:5 | b | +| D.cpp:37:8:37:10 | box | +| D.cpp:37:21:37:21 | e | +| D.cpp:38:14:38:14 | b | +| D.cpp:44:5:44:5 | b | +| D.cpp:44:8:44:14 | call to getBox1 | +| D.cpp:44:19:44:22 | elem | +| D.cpp:45:14:45:14 | b | +| D.cpp:51:5:51:5 | b | +| D.cpp:51:8:51:14 | call to getBox1 | +| D.cpp:51:27:51:27 | e | +| D.cpp:52:14:52:14 | b | +| D.cpp:57:5:57:12 | boxfield | +| D.cpp:57:5:57:12 | this | +| D.cpp:58:5:58:12 | boxfield | +| D.cpp:58:5:58:12 | this | +| D.cpp:58:15:58:17 | box | +| D.cpp:58:20:58:23 | elem | +| D.cpp:59:5:59:7 | this | +| D.cpp:64:10:64:17 | boxfield | +| D.cpp:64:10:64:17 | this | +| D.cpp:64:20:64:22 | box | +| D.cpp:64:25:64:28 | elem | +| E.cpp:21:10:21:10 | p | +| E.cpp:21:13:21:16 | data | +| E.cpp:21:18:21:23 | buffer | +| E.cpp:28:21:28:23 | raw | +| E.cpp:29:21:29:21 | b | +| E.cpp:29:24:29:29 | buffer | +| E.cpp:30:21:30:21 | p | +| E.cpp:30:23:30:26 | data | +| E.cpp:30:28:30:33 | buffer | +| E.cpp:31:10:31:12 | raw | +| E.cpp:32:10:32:10 | b | +| E.cpp:32:13:32:18 | buffer | +| E.cpp:33:18:33:19 | & ... | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:9:6:9:7 | m1 | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:13:5:13:6 | m1 | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:17:5:17:6 | m1 | +| aliasing.cpp:25:17:25:19 | & ... | +| aliasing.cpp:26:19:26:20 | s2 | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:37:8:37:9 | m1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:42:6:42:7 | m1 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:49:9:49:10 | m1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:54:6:54:7 | m1 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:60:6:60:7 | m1 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:72:5:72:6 | m1 | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:79:6:79:7 | m1 | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:86:5:86:6 | m1 | +| aliasing.cpp:92:3:92:3 | w | +| aliasing.cpp:92:5:92:5 | s | +| aliasing.cpp:92:7:92:8 | m1 | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:12:8:12:8 | a | +| by_reference.cpp:16:5:16:8 | this | +| by_reference.cpp:16:11:16:11 | a | +| by_reference.cpp:20:5:20:8 | this | +| by_reference.cpp:20:23:20:27 | value | +| by_reference.cpp:24:19:24:22 | this | +| by_reference.cpp:24:25:24:29 | value | +| by_reference.cpp:50:3:50:3 | s | +| by_reference.cpp:50:17:50:26 | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | s | +| by_reference.cpp:56:19:56:28 | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | s | +| by_reference.cpp:62:25:62:34 | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | & ... | +| by_reference.cpp:68:21:68:30 | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:84:10:84:10 | a | +| by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:88:9:88:9 | a | +| by_reference.cpp:102:21:102:39 | & ... | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:103:21:103:25 | outer | +| by_reference.cpp:103:27:103:35 | inner_ptr | +| by_reference.cpp:104:15:104:22 | & ... | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:21:106:41 | & ... | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:107:21:107:26 | pouter | +| by_reference.cpp:107:29:107:37 | inner_ptr | +| by_reference.cpp:108:15:108:24 | & ... | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:110:8:110:12 | outer | +| by_reference.cpp:110:14:110:25 | inner_nested | +| by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:111:8:111:12 | outer | +| by_reference.cpp:111:14:111:22 | inner_ptr | +| by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:112:8:112:12 | outer | +| by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:114:8:114:13 | pouter | +| by_reference.cpp:114:16:114:27 | inner_nested | +| by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:115:8:115:13 | pouter | +| by_reference.cpp:115:16:115:24 | inner_ptr | +| by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:116:8:116:13 | pouter | +| by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:122:27:122:38 | inner_nested | +| by_reference.cpp:123:21:123:36 | * ... | +| by_reference.cpp:123:22:123:26 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:124:21:124:21 | a | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:126:29:126:40 | inner_nested | +| by_reference.cpp:127:21:127:38 | * ... | +| by_reference.cpp:127:22:127:27 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | +| by_reference.cpp:128:23:128:23 | a | +| by_reference.cpp:130:8:130:12 | outer | +| by_reference.cpp:130:14:130:25 | inner_nested | +| by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer | +| by_reference.cpp:131:14:131:22 | inner_ptr | +| by_reference.cpp:131:25:131:25 | a | +| by_reference.cpp:132:8:132:12 | outer | +| by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter | +| by_reference.cpp:134:16:134:27 | inner_nested | +| by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter | +| by_reference.cpp:135:16:135:24 | inner_ptr | +| by_reference.cpp:135:27:135:27 | a | +| by_reference.cpp:136:8:136:13 | pouter | +| by_reference.cpp:136:16:136:16 | a | +| complex.cpp:11:22:11:23 | a_ | +| complex.cpp:11:22:11:23 | this | +| complex.cpp:12:22:12:23 | b_ | +| complex.cpp:12:22:12:23 | this | +| complex.cpp:51:8:51:8 | b | +| complex.cpp:51:10:51:14 | inner | +| complex.cpp:51:16:51:16 | f | +| complex.cpp:52:8:52:8 | b | +| complex.cpp:52:10:52:14 | inner | +| complex.cpp:52:16:52:16 | f | +| complex.cpp:62:3:62:4 | b1 | +| complex.cpp:62:6:62:10 | inner | +| complex.cpp:62:12:62:12 | f | +| complex.cpp:63:3:63:4 | b2 | +| complex.cpp:63:6:63:10 | inner | +| complex.cpp:63:12:63:12 | f | +| complex.cpp:64:3:64:4 | b3 | +| complex.cpp:64:6:64:10 | inner | +| complex.cpp:64:12:64:12 | f | +| complex.cpp:65:3:65:4 | b3 | +| complex.cpp:65:6:65:10 | inner | +| complex.cpp:65:12:65:12 | f | +| complex.cpp:68:7:68:8 | b1 | +| complex.cpp:71:7:71:8 | b2 | +| complex.cpp:74:7:74:8 | b3 | +| complex.cpp:77:7:77:8 | b4 | +| constructors.cpp:20:24:20:25 | a_ | +| constructors.cpp:20:24:20:25 | this | +| constructors.cpp:21:24:21:25 | b_ | +| constructors.cpp:21:24:21:25 | this | +| constructors.cpp:28:10:28:10 | f | +| constructors.cpp:29:10:29:10 | f | +| constructors.cpp:40:9:40:9 | f | +| constructors.cpp:43:9:43:9 | g | +| constructors.cpp:46:9:46:9 | h | +| constructors.cpp:49:9:49:9 | i | +| qualifiers.cpp:9:30:9:33 | this | +| qualifiers.cpp:9:36:9:36 | a | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:12:56:12:56 | a | +| qualifiers.cpp:13:51:13:55 | inner | +| qualifiers.cpp:13:57:13:57 | a | +| qualifiers.cpp:22:5:22:9 | outer | +| qualifiers.cpp:22:11:22:18 | call to getInner | +| qualifiers.cpp:22:23:22:23 | a | +| qualifiers.cpp:23:10:23:14 | outer | +| qualifiers.cpp:23:16:23:20 | inner | +| qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | outer | +| qualifiers.cpp:27:11:27:18 | call to getInner | +| qualifiers.cpp:27:28:27:37 | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer | +| qualifiers.cpp:28:16:28:20 | inner | +| qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | outer | +| qualifiers.cpp:32:23:32:30 | call to getInner | +| qualifiers.cpp:32:35:32:44 | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer | +| qualifiers.cpp:33:16:33:20 | inner | +| qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | * ... | +| qualifiers.cpp:37:20:37:24 | outer | +| qualifiers.cpp:37:38:37:47 | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer | +| qualifiers.cpp:38:16:38:20 | inner | +| qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:6:42:22 | * ... | +| qualifiers.cpp:42:7:42:11 | outer | +| qualifiers.cpp:42:25:42:25 | a | +| qualifiers.cpp:43:10:43:14 | outer | +| qualifiers.cpp:43:16:43:20 | inner | +| qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:6:47:11 | & ... | +| qualifiers.cpp:47:15:47:22 | call to getInner | +| qualifiers.cpp:47:27:47:27 | a | +| qualifiers.cpp:48:10:48:14 | outer | +| qualifiers.cpp:48:16:48:20 | inner | +| qualifiers.cpp:48:23:48:23 | a | +| simple.cpp:20:24:20:25 | a_ | +| simple.cpp:20:24:20:25 | this | +| simple.cpp:21:24:21:25 | b_ | +| simple.cpp:21:24:21:25 | this | +| simple.cpp:28:10:28:10 | f | +| simple.cpp:29:10:29:10 | f | +| simple.cpp:39:5:39:5 | f | +| simple.cpp:40:5:40:5 | g | +| simple.cpp:41:5:41:5 | h | +| simple.cpp:42:5:42:5 | h | +| simple.cpp:45:9:45:9 | f | +| simple.cpp:48:9:48:9 | g | +| simple.cpp:51:9:51:9 | h | +| simple.cpp:54:9:54:9 | i | +| simple.cpp:65:5:65:5 | a | +| simple.cpp:65:7:65:7 | i | +| simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:9:83:10 | this | +| simple.cpp:83:12:83:13 | f1 | +| simple.cpp:84:14:84:20 | this | +| struct_init.c:15:8:15:9 | ab | +| struct_init.c:15:12:15:12 | a | +| struct_init.c:16:8:16:9 | ab | +| struct_init.c:16:12:16:12 | b | +| struct_init.c:22:8:22:9 | ab | +| struct_init.c:22:11:22:11 | a | +| struct_init.c:23:8:23:9 | ab | +| struct_init.c:23:11:23:11 | b | +| struct_init.c:24:10:24:12 | & ... | +| struct_init.c:31:8:31:12 | outer | +| struct_init.c:31:14:31:21 | nestedAB | +| struct_init.c:31:23:31:23 | a | +| struct_init.c:32:8:32:12 | outer | +| struct_init.c:32:14:32:21 | nestedAB | +| struct_init.c:32:23:32:23 | b | +| struct_init.c:33:8:33:12 | outer | +| struct_init.c:33:14:33:22 | pointerAB | +| struct_init.c:33:25:33:25 | a | +| struct_init.c:34:8:34:12 | outer | +| struct_init.c:34:14:34:22 | pointerAB | +| struct_init.c:34:25:34:25 | b | +| struct_init.c:36:10:36:24 | & ... | +| struct_init.c:36:11:36:15 | outer | +| struct_init.c:46:10:46:14 | outer | +| struct_init.c:46:16:46:24 | pointerAB | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql new file mode 100644 index 00000000000..8acd1f3e5fe --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected new file mode 100644 index 00000000000..d505ff5d87e --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -0,0 +1,838 @@ +edges +| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | +| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c | +| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | +| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | +| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | +| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] | +| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | +| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] | +| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] | +| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] | +| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c | +| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] | +| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] | +| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... | +| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] | +| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] | +| A.cpp:101:8:101:9 | c1 [a] | A.cpp:103:14:103:14 | c [a] | +| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] | +| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | +| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | +| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | +| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] | +| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | +| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | +| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | +| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] | +| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... | +| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] | +| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] | +| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] | +| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... | +| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | +| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] | +| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] | +| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] | +| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] | +| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b | +| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] | +| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c | +| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c | +| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b | +| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] | +| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | +| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] | +| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] | +| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | +| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] | +| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] | +| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head | +| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] | +| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] | +| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] | +| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] | +| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head | +| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e | +| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] | +| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] | +| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] | +| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | +| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] | +| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 | +| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e | +| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] | +| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] | +| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] | +| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | +| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] | +| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 | +| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] | +| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] | +| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] | +| C.cpp:19:5:19:5 | c [s3] | C.cpp:27:8:27:11 | this [s3] | +| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | C.cpp:18:12:18:18 | call to C [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | +| C.cpp:24:5:24:8 | this [post update] [s3] | C.cpp:18:12:18:18 | call to C [s3] | +| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | this [post update] [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... | +| C.cpp:27:8:27:11 | this [s1] | C.cpp:29:10:29:11 | this [s1] | +| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] | +| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 | +| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] | +| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] | +| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem | +| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... | +| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] | +| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] | +| D.cpp:30:8:30:10 | box [post update] [elem] | D.cpp:30:5:30:5 | b [post update] [box, elem] | +| D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | +| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | +| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] | +| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | +| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] | +| D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] | +| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | +| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | +| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | +| D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] | +| D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | +| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | +| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | +| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] | +| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] | +| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem | +| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] | +| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] | +| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer | +| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | +| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] | +| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] | +| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] | +| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] | +| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] | +| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer | +| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] | +| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | +| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... | +| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | +| aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... | +| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] | +| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] | +| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] | +| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... | +| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] | +| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] | +| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | +| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | +| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | +| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | +| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] | +| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] | +| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | +| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a | +| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | +| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | complex.cpp:51:10:51:14 | inner [f, a_] | +| complex.cpp:51:10:51:14 | inner [f, a_] | complex.cpp:51:16:51:16 | f [a_] | +| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:18:51:18 | call to a | +| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | complex.cpp:52:10:52:14 | inner [f, b_] | +| complex.cpp:52:10:52:14 | inner [f, b_] | complex.cpp:52:16:52:16 | f [b_] | +| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:18:52:18 | call to b | +| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | +| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | +| complex.cpp:62:12:62:12 | ref arg f [a_] | complex.cpp:62:6:62:10 | inner [post update] [f, a_] | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | ref arg f [a_] | +| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | +| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | +| complex.cpp:63:12:63:12 | ref arg f [b_] | complex.cpp:63:6:63:10 | inner [post update] [f, b_] | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | ref arg f [b_] | +| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | +| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:64:12:64:12 | ref arg f [a_] | complex.cpp:64:6:64:10 | inner [post update] [f, a_] | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | ref arg f [a_] | +| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | +| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:65:12:65:12 | ref arg f [b_] | complex.cpp:65:6:65:10 | inner [post update] [f, b_] | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | ref arg f [b_] | +| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] | +| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] | +| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a | +| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] | +| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] | +| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] | +| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] | +| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | +| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | +| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | +| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | +| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | +| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] | +| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | +| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | +| simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | +| simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] | +| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | +| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | +| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | +| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] | +| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a | +| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] | +| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] | +| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] | +| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] | +| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a | +| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] | +| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a | +| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | +| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] | +| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] | +| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] | +| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] | +| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] | +| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] | +| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] | +| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] | +nodes +| A.cpp:41:15:41:21 | new | semmle.label | new | +| A.cpp:43:10:43:12 | & ... | semmle.label | & ... | +| A.cpp:47:12:47:18 | new | semmle.label | new | +| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] | +| A.cpp:48:20:48:20 | c | semmle.label | c | +| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | +| A.cpp:49:13:49:13 | c | semmle.label | c | +| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:55:12:55:19 | new | semmle.label | new | +| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] | +| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] | +| A.cpp:57:17:57:23 | new | semmle.label | new | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | +| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] | +| A.cpp:64:21:64:28 | new | semmle.label | new | +| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] | +| A.cpp:66:14:66:14 | c | semmle.label | c | +| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] | +| A.cpp:73:25:73:32 | new | semmle.label | new | +| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] | +| A.cpp:75:14:75:14 | c | semmle.label | c | +| A.cpp:98:12:98:18 | new | semmle.label | new | +| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] | +| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... | +| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] | +| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:120:16:120:16 | a | semmle.label | a | +| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | +| A.cpp:132:13:132:13 | c | semmle.label | c | +| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] | +| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] | +| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... | +| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] | +| A.cpp:143:25:143:31 | new | semmle.label | new | +| A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] | +| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] | +| A.cpp:151:18:151:18 | b | semmle.label | b | +| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] | +| A.cpp:152:13:152:13 | b | semmle.label | b | +| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] | +| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] | +| A.cpp:153:16:153:16 | c | semmle.label | c | +| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:159:12:159:18 | new | semmle.label | new | +| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] | +| A.cpp:160:29:160:29 | b | semmle.label | b | +| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] | +| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] | +| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] | +| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] | +| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] | +| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] | +| A.cpp:165:26:165:29 | head | semmle.label | head | +| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] | +| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] | +| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] | +| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] | +| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] | +| A.cpp:169:15:169:18 | head | semmle.label | head | +| B.cpp:6:15:6:24 | new | semmle.label | new | +| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] | +| B.cpp:7:25:7:25 | e | semmle.label | e | +| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] | +| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] | +| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] | +| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] | +| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 | +| B.cpp:15:15:15:27 | new | semmle.label | new | +| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] | +| B.cpp:16:37:16:37 | e | semmle.label | e | +| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] | +| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] | +| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] | +| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] | +| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 | +| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] | +| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] | +| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] | +| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] | +| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] | +| C.cpp:22:12:22:21 | new | semmle.label | new | +| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] | +| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... | +| C.cpp:24:16:24:25 | new | semmle.label | new | +| C.cpp:27:8:27:11 | this [s1] | semmle.label | this [s1] | +| C.cpp:27:8:27:11 | this [s3] | semmle.label | this [s3] | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | +| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] | +| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] | +| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] | +| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] | +| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem | +| D.cpp:28:15:28:24 | new | semmle.label | new | +| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... | +| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:35:15:35:24 | new | semmle.label | new | +| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] | +| D.cpp:37:21:37:21 | e | semmle.label | e | +| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:42:15:42:24 | new | semmle.label | new | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | +| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:49:15:49:24 | new | semmle.label | new | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] | +| D.cpp:51:27:51:27 | e | semmle.label | e | +| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:56:15:56:24 | new | semmle.label | new | +| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] | +| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... | +| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] | +| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] | +| D.cpp:64:25:64:28 | elem | semmle.label | elem | +| E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] | +| E.cpp:21:10:21:10 | p [data, buffer] | semmle.label | p [data, buffer] | +| E.cpp:21:13:21:16 | data [buffer] | semmle.label | data [buffer] | +| E.cpp:21:18:21:23 | buffer | semmle.label | buffer | +| E.cpp:28:21:28:23 | ref arg raw | semmle.label | ref arg raw | +| E.cpp:29:21:29:21 | b [post update] [buffer] | semmle.label | b [post update] [buffer] | +| E.cpp:29:24:29:29 | ref arg buffer | semmle.label | ref arg buffer | +| E.cpp:30:21:30:21 | p [post update] [data, buffer] | semmle.label | p [post update] [data, buffer] | +| E.cpp:30:23:30:26 | data [post update] [buffer] | semmle.label | data [post update] [buffer] | +| E.cpp:30:28:30:33 | ref arg buffer | semmle.label | ref arg buffer | +| E.cpp:31:10:31:12 | raw | semmle.label | raw | +| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] | +| E.cpp:32:13:32:18 | buffer | semmle.label | buffer | +| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] | +| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] | +| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] | +| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] | +| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] | +| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | +| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | +| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | +| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:115:27:115:27 | a | semmle.label | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:131:25:131:25 | a | semmle.label | a | +| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | +| by_reference.cpp:132:14:132:14 | a | semmle.label | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:135:27:135:27 | a | semmle.label | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | +| by_reference.cpp:136:16:136:16 | a | semmle.label | a | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:51:10:51:14 | inner [f, a_] | semmle.label | inner [f, a_] | +| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] | +| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | +| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:52:10:52:14 | inner [f, b_] | semmle.label | inner [f, b_] | +| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] | +| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | +| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | semmle.label | b1 [post update] [inner, f, ... (3)] | +| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:62:12:62:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | semmle.label | b2 [post update] [inner, f, ... (3)] | +| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:63:12:63:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:64:12:64:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:65:12:65:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | semmle.label | b1 [inner, f, ... (3)] | +| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | semmle.label | b2 [inner, f, ... (3)] | +| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | semmle.label | b3 [inner, f, ... (3)] | +| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | +| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | +| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] | +| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | +| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | +| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:23:23:23:23 | a | semmle.label | a | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:28:23:28:23 | a | semmle.label | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:33:23:33:23 | a | semmle.label | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:38:23:38:23 | a | semmle.label | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:43:23:43:23 | a | semmle.label | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:48:23:48:23 | a | semmle.label | a | +| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | +| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | +| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | +| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | +| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | +| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | +| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] | +| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] | +| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... | +| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | +| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | +| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | +| struct_init.c:15:12:15:12 | a | semmle.label | a | +| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] | +| struct_init.c:22:11:22:11 | a | semmle.label | a | +| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | +| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | +| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] | +| struct_init.c:31:23:31:23 | a | semmle.label | a | +| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | +| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] | +| struct_init.c:33:25:33:25 | a | semmle.label | a | +| struct_init.c:36:10:36:24 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:36:11:36:15 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | +| struct_init.c:36:17:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | +| struct_init.c:40:17:40:36 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | +| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | +| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] | +#select +| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new | +| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | +| A.cpp:66:14:66:14 | c | A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | c flows from $@ | A.cpp:64:21:64:28 | new | new | +| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new | +| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | +| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | +| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | +| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new | +| B.cpp:19:20:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new | +| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | +| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:42:15:42:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:49:15:49:24 | new | new | +| D.cpp:64:25:64:28 | elem | D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | elem flows from $@ | D.cpp:56:15:56:24 | new | new | +| E.cpp:21:18:21:23 | buffer | E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | buffer flows from $@ | E.cpp:30:28:30:33 | ref arg buffer | ref arg buffer | +| E.cpp:31:10:31:12 | raw | E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | raw flows from $@ | E.cpp:28:21:28:23 | ref arg raw | ref arg raw | +| E.cpp:32:13:32:18 | buffer | E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | buffer flows from $@ | E.cpp:29:24:29:29 | ref arg buffer | ref arg buffer | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | +| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | +| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input | +| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | +| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | +| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | +| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c:33:25:33:25 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql new file mode 100644 index 00000000000..1dcccc6aa06 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import semmle.code.cpp.dataflow.DataFlow +import ASTConfiguration +import cpp +import DataFlow::PathGraph + +from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(src, sink) +select sink, src, sink, sink + " flows from $@", src, src.toString() diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp new file mode 100644 index 00000000000..dd7baac2933 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -0,0 +1,50 @@ +void sink(void *o); +void *user_input(void); + +namespace qualifiers { + + struct Inner { + void *a; + + void setA(void *value) { this->a = value; } + }; + + void pointerSetA(Inner *inner, void *value) { inner->a = value; } + void referenceSetA(Inner &inner, void *value) { inner.a = value; } + + struct Outer { + Inner *inner; + + Inner *getInner() { return inner; } + }; + + void assignToGetter(Outer outer) { + outer.getInner()->a = user_input(); + sink(outer.inner->a); // $ast $f-:ir + } + + void getterArgument1(Outer outer) { + outer.getInner()->setA(user_input()); + sink(outer.inner->a); // $ast $f-:ir + } + + void getterArgument2(Outer outer) { + pointerSetA(outer.getInner(), user_input()); + sink(outer.inner->a); // $ast $f-:ir + } + + void getterArgument2Ref(Outer outer) { + referenceSetA(*outer.getInner(), user_input()); + sink(outer.inner->a); // $ast $f-:ir + } + + void assignToGetterStar(Outer outer) { + (*outer.getInner()).a = user_input(); + sink(outer.inner->a); // $ast $f-:ir + } + + void assignToGetterAmp(Outer outer) { + (&outer)->getInner()->a = user_input(); + sink(outer.inner->a); // $ast $f-:ir + } +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 64b6748d0d5..342a1100aa6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); // flow (through `f.setA` and `h.setA`) - sink(f.b()); // flow (through `g.setB` and `h.setB`) + sink(f.a()); //$ast=39:12 $ast=41:12 $ir=39:12 $ir=41:12 + sink(f.b()); //$ast=40:12 $ast=42:12 $ir=40:12 $ir=42:12 } void foo() @@ -64,7 +64,25 @@ void single_field_test() A a; a.i = user_input(); A a2 = a; - sink(a2.i); + sink(a2.i); //$ast,ir } +struct C { + int f1; +}; + +struct C2 +{ + C f2; + + int getf2f1() { + return f2.f1; + } + + void m() { + f2.f1 = user_input(); + sink(getf2f1()); //$ast,ir + } +}; + } // namespace Simple diff --git a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c index 2d044cf79d8..891be43cab2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c +++ b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c @@ -12,14 +12,14 @@ struct Outer { }; void absink(struct AB *ab) { - sink(ab->a); // flow (three sources) + sink(ab->a); //$ast,ir=20:20 $ast,ir=27:7 $ast=40:20 $f-:ir sink(ab->b); // no flow } int struct_init(void) { struct AB ab = { user_input(), 0 }; - sink(ab.a); // flow + sink(ab.a); //$ast,ir sink(ab.b); // no flow absink(&ab); @@ -28,9 +28,9 @@ int struct_init(void) { &ab, }; - sink(outer.nestedAB.a); // flow + sink(outer.nestedAB.a); //$ast,ir sink(outer.nestedAB.b); // no flow - sink(outer.pointerAB->a); // flow + sink(outer.pointerAB->a); //$ast $f-:ir sink(outer.pointerAB->b); // no flow absink(&outer.nestedAB); diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected index aba01f08072..cebcec65a7c 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected @@ -1,5 +1,8 @@ | partialdefinitions.cpp:14:2:14:2 | partial def of s | partialdefinitions.cpp:14:2:14:2 | s | partialdefinitions.cpp:14:2:14:8 | ... = ... | +| partialdefinitions.cpp:14:4:14:4 | partial def of x | partialdefinitions.cpp:14:4:14:4 | x | partialdefinitions.cpp:14:2:14:8 | ... = ... | | partialdefinitions.cpp:15:2:15:2 | partial def of s | partialdefinitions.cpp:15:2:15:2 | s | partialdefinitions.cpp:15:2:15:10 | ... = ... | | partialdefinitions.cpp:15:4:15:4 | partial def of y | partialdefinitions.cpp:15:4:15:4 | y | partialdefinitions.cpp:15:2:15:10 | ... = ... | -| partialdefinitions.cpp:22:29:22:32 | partial def of this | file://:0:0:0:0 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | -| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:3:27:7 | myInt | +| partialdefinitions.cpp:15:6:15:6 | partial def of z | partialdefinitions.cpp:15:6:15:6 | z | partialdefinitions.cpp:15:2:15:10 | ... = ... | +| partialdefinitions.cpp:22:29:22:32 | partial def of data | partialdefinitions.cpp:22:29:22:32 | data | partialdefinitions.cpp:22:29:22:40 | ... = ... | +| partialdefinitions.cpp:22:29:22:32 | partial def of this | partialdefinitions.cpp:22:29:22:32 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | +| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:9:27:15 | call to setData | diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql index bc14c655159..0fa8c99fde1 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar from PartialDefinition def -select def.getActualLocation().toString(), "partial def of " + def.toString(), def.getDefinedExpr(), +select def.getActualLocation().toString(), "partial def of " + def.toString(), def, def.getSubBasicBlockStart() diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp new file mode 100644 index 00000000000..d5745bcb713 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -0,0 +1,69 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClass { +public: + MyCopyableClass() {} // Constructor + MyCopyableClass(int _v) : v(_v) {} // ConversionConstructor + MyCopyableClass(const MyCopyableClass &other) : v(other.v) {} // CopyConstructor + MyCopyableClass &operator=(const MyCopyableClass &other) { // CopyAssignmentOperator + v = other.v; + return *this; + } + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClass s1(1); + MyCopyableClass s2 = 1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1(source()); + MyCopyableClass s2 = source(); + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + MyCopyableClass s1; + MyCopyableClass s2 = s1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1 = MyCopyableClass(source()); + MyCopyableClass s2; + MyCopyableClass s3; + s2 = MyCopyableClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp new file mode 100644 index 00000000000..67f6a45fbe7 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp @@ -0,0 +1,69 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClassDeclOnly { +public: + MyCopyableClassDeclOnly(); // Constructor + MyCopyableClassDeclOnly(int _v); // ConversionConstructor + MyCopyableClassDeclOnly(const MyCopyableClassDeclOnly &other); // CopyConstructor + MyCopyableClassDeclOnly &operator=(const MyCopyableClassDeclOnly &other); // CopyAssignmentOperator + + + + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClassDeclOnly s1(1); + MyCopyableClassDeclOnly s2 = 1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1(source()); + MyCopyableClassDeclOnly s2 = source(); + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + MyCopyableClassDeclOnly s1; + MyCopyableClassDeclOnly s2 = s1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1 = MyCopyableClassDeclOnly(source()); + MyCopyableClassDeclOnly s2; + MyCopyableClassDeclOnly s3; + s2 = MyCopyableClassDeclOnly(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 2080707f17f..90bbb1ca0cd 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -15,10 +15,14 @@ int vsnprintf(char *s, size_t n, const char *format, va_list arg); int mysprintf(char *s, size_t n, const char *format, ...) { + int result; + va_list args; va_start(args, format); - vsnprintf(s, n, format, args); + result = vsnprintf(s, n, format, args); va_end(args); + + return result; } int sscanf(const char *s, const char *format, ...); @@ -132,3 +136,24 @@ void test1() sink(buffer); // tainted [NOT DETECTED] } } + +// ---------- + +size_t strlen(const char *s); +size_t wcslen(const wchar_t *s); + +void test2() +{ + char *s = string::source(); + wchar_t *ws = wstring::source(); + int i; + + sink(strlen(s)); + sink(wcslen(ws)); + + i = strlen(s) + 1; + sink(i); + + sink(s[strlen(s) - 1]); // tainted + sink(ws + (wcslen(ws) / 2)); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 524884a2d20..94e9bfed22e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,110 +1,311 @@ +| copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| copyableclass.cpp:8:22:8:23 | _v | copyableclass.cpp:8:30:8:31 | _v | | +| copyableclass.cpp:8:30:8:31 | _v | copyableclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| copyableclass.cpp:9:2:9:16 | this | copyableclass.cpp:9:50:9:59 | constructor init of field v [pre-this] | | +| copyableclass.cpp:9:41:9:45 | other | copyableclass.cpp:9:52:9:56 | other | | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:50:9:59 | constructor init of field v | TAINT | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:58:9:58 | v | | +| copyableclass.cpp:10:19:10:27 | this | copyableclass.cpp:11:3:11:3 | this | | +| copyableclass.cpp:10:52:10:56 | other | copyableclass.cpp:11:7:11:11 | other | | +| copyableclass.cpp:11:3:11:3 | this | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:3:11:3 | this [post update] | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:13:11:13 | v | copyableclass.cpp:11:3:11:13 | ... = ... | | +| copyableclass.cpp:12:11:12:14 | this | copyableclass.cpp:12:10:12:14 | * ... | TAINT | +| copyableclass.cpp:21:22:21:22 | 1 | copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:23:22:23:23 | s1 | | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s1 | | +| copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s2 | | +| copyableclass.cpp:22:24:22:24 | 1 | copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:23:22:23:23 | s1 | copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | | +| copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s3 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | s4 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:3:25:4 | ref arg s4 | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:8:25:8 | 1 | copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass.cpp:34:22:34:27 | call to source | copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:36:22:36:23 | s1 | | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s1 | | +| copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s2 | | +| copyableclass.cpp:35:24:35:29 | call to source | copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:36:22:36:23 | s1 | copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | | +| copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s3 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | s4 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:3:38:4 | ref arg s4 | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:8:38:13 | call to source | copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:48:24:48:25 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:49:22:49:23 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:51:8:51:9 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s1 | | +| copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s2 | | +| copyableclass.cpp:48:24:48:25 | s1 | copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:23 | s1 | copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s3 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:51:3:51:4 | s4 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:3:51:4 | ref arg s4 | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s1 | | +| copyableclass.cpp:60:40:60:45 | call to source | copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | s2 | | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:62:19:62:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | s3 | | +| copyableclass.cpp:63:3:63:4 | ref arg s2 | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass.cpp:63:24:63:29 | call to source | copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:18 | call to source | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:11:67:11 | call to operator= | TAINT | +| copyableclass_declonly.cpp:21:30:21:30 | 1 | copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:23:30:23:31 | s1 | | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:27:8:27:9 | s1 | | +| copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:28:8:28:9 | s2 | | +| copyableclass_declonly.cpp:22:32:22:32 | 1 | copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:23:30:23:31 | s1 | copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:29:8:29:9 | s3 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | s4 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:8:25:8 | 1 | copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:34:30:34:35 | call to source | copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:36:30:36:31 | s1 | | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:40:8:40:9 | s1 | | +| copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:41:8:41:9 | s2 | | +| copyableclass_declonly.cpp:35:32:35:37 | call to source | copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:36:30:36:31 | s1 | copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:42:8:42:9 | s3 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | s4 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:8:38:13 | call to source | copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:48:32:48:33 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:49:30:49:31 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:8:51:9 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:53:8:53:9 | s1 | | +| copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:54:8:54:9 | s2 | | +| copyableclass_declonly.cpp:48:32:48:33 | s1 | copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:31 | s1 | copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:55:8:55:9 | s3 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:3:51:4 | s4 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:65:8:65:9 | s1 | | +| copyableclass_declonly.cpp:60:56:60:61 | call to source | copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | s2 | | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:62:27:62:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | s3 | | +| copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:63:32:63:37 | call to source | copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | -| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | | -| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | | -| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | | -| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | | -| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | | -| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | | -| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT | -| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | | -| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | | -| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | | -| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT | -| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | | -| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | | -| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | | -| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT | -| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | | -| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | | -| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | | -| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT | -| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | | -| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | | -| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | | -| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT | -| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | | -| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | | -| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | | -| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT | -| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | | -| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | | -| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | | -| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT | -| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | | -| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | | -| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | | -| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT | -| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | | -| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | | -| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | | -| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT | -| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | | -| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | | -| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | | -| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT | -| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | | -| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | | -| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | | -| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT | -| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | | -| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | | -| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT | -| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | | -| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | | -| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT | -| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | | -| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | | -| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | | -| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | | -| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | | -| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | | -| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | | -| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | | -| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | | -| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | | -| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | | -| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT | -| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | | -| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | | -| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | | -| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | | -| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT | -| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | | -| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | +| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | +| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | +| format.cpp:20:10:20:13 | args | format.cpp:22:36:22:39 | args | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:22:3:22:40 | ... = ... | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:25:9:25:14 | result | | +| format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | +| format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | +| format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | +| format.cpp:51:17:51:22 | ref arg buffer | format.cpp:52:8:52:13 | buffer | | +| format.cpp:51:30:51:33 | %s | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:51:36:51:43 | Hello. | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:55:21:55:24 | {...} | format.cpp:56:17:56:22 | buffer | | +| format.cpp:55:21:55:24 | {...} | format.cpp:57:8:57:13 | buffer | | +| format.cpp:55:23:55:23 | 0 | format.cpp:55:21:55:24 | {...} | TAINT | +| format.cpp:56:17:56:22 | ref arg buffer | format.cpp:57:8:57:13 | buffer | | +| format.cpp:56:30:56:33 | %s | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:56:36:56:49 | call to source | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:60:21:60:24 | {...} | format.cpp:61:17:61:22 | buffer | | +| format.cpp:60:21:60:24 | {...} | format.cpp:62:8:62:13 | buffer | | +| format.cpp:60:23:60:23 | 0 | format.cpp:60:21:60:24 | {...} | TAINT | +| format.cpp:61:17:61:22 | ref arg buffer | format.cpp:62:8:62:13 | buffer | | +| format.cpp:61:30:61:43 | call to source | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:61:48:61:55 | Hello. | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:65:21:65:24 | {...} | format.cpp:66:17:66:22 | buffer | | +| format.cpp:65:21:65:24 | {...} | format.cpp:67:8:67:13 | buffer | | +| format.cpp:65:23:65:23 | 0 | format.cpp:65:21:65:24 | {...} | TAINT | +| format.cpp:66:17:66:22 | ref arg buffer | format.cpp:67:8:67:13 | buffer | | +| format.cpp:66:30:66:39 | %s %s %s | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:42:66:44 | a | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:47:66:49 | b | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:52:66:65 | call to source | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:70:21:70:24 | {...} | format.cpp:71:17:71:22 | buffer | | +| format.cpp:70:21:70:24 | {...} | format.cpp:72:8:72:13 | buffer | | +| format.cpp:70:23:70:23 | 0 | format.cpp:70:21:70:24 | {...} | TAINT | +| format.cpp:71:17:71:22 | ref arg buffer | format.cpp:72:8:72:13 | buffer | | +| format.cpp:71:30:71:35 | %.*s | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:38:71:39 | 10 | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:42:71:55 | call to source | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:76:21:76:24 | {...} | format.cpp:77:17:77:22 | buffer | | +| format.cpp:76:21:76:24 | {...} | format.cpp:78:8:78:13 | buffer | | +| format.cpp:76:23:76:23 | 0 | format.cpp:76:21:76:24 | {...} | TAINT | +| format.cpp:77:17:77:22 | ref arg buffer | format.cpp:78:8:78:13 | buffer | | +| format.cpp:77:30:77:33 | %i | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:77:36:77:36 | 0 | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:81:21:81:24 | {...} | format.cpp:82:17:82:22 | buffer | | +| format.cpp:81:21:81:24 | {...} | format.cpp:83:8:83:13 | buffer | | +| format.cpp:81:23:81:23 | 0 | format.cpp:81:21:81:24 | {...} | TAINT | +| format.cpp:82:17:82:22 | ref arg buffer | format.cpp:83:8:83:13 | buffer | | +| format.cpp:82:30:82:33 | %i | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:82:36:82:41 | call to source | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:86:21:86:24 | {...} | format.cpp:87:17:87:22 | buffer | | +| format.cpp:86:21:86:24 | {...} | format.cpp:88:8:88:13 | buffer | | +| format.cpp:86:23:86:23 | 0 | format.cpp:86:21:86:24 | {...} | TAINT | +| format.cpp:87:17:87:22 | ref arg buffer | format.cpp:88:8:88:13 | buffer | | +| format.cpp:87:30:87:35 | %.*s | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:38:87:43 | call to source | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:48:87:55 | Hello. | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:92:21:92:24 | {...} | format.cpp:93:17:93:22 | buffer | | +| format.cpp:92:21:92:24 | {...} | format.cpp:94:8:94:13 | buffer | | +| format.cpp:92:23:92:23 | 0 | format.cpp:92:21:92:24 | {...} | TAINT | +| format.cpp:93:17:93:22 | ref arg buffer | format.cpp:94:8:94:13 | buffer | | +| format.cpp:93:30:93:33 | %p | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:93:36:93:49 | call to source | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:98:21:98:24 | {...} | format.cpp:99:16:99:21 | buffer | | +| format.cpp:98:21:98:24 | {...} | format.cpp:100:8:100:13 | buffer | | +| format.cpp:98:23:98:23 | 0 | format.cpp:98:21:98:24 | {...} | TAINT | +| format.cpp:99:16:99:21 | ref arg buffer | format.cpp:100:8:100:13 | buffer | | +| format.cpp:99:24:99:27 | %s | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:99:30:99:43 | call to source | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:103:21:103:24 | {...} | format.cpp:104:16:104:21 | buffer | | +| format.cpp:103:21:103:24 | {...} | format.cpp:105:8:105:13 | buffer | | +| format.cpp:103:23:103:23 | 0 | format.cpp:103:21:103:24 | {...} | TAINT | +| format.cpp:104:16:104:21 | ref arg buffer | format.cpp:105:8:105:13 | buffer | | +| format.cpp:104:24:104:28 | %ls | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:104:31:104:45 | call to source | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:108:25:108:28 | {...} | format.cpp:109:17:109:23 | wbuffer | | +| format.cpp:108:25:108:28 | {...} | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:108:27:108:27 | 0 | format.cpp:108:25:108:28 | {...} | TAINT | +| format.cpp:109:17:109:23 | ref arg wbuffer | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:109:31:109:35 | %s | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:109:38:109:52 | call to source | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:113:21:113:24 | {...} | format.cpp:114:18:114:23 | buffer | | +| format.cpp:113:21:113:24 | {...} | format.cpp:115:8:115:13 | buffer | | +| format.cpp:113:23:113:23 | 0 | format.cpp:113:21:113:24 | {...} | TAINT | +| format.cpp:114:18:114:23 | ref arg buffer | format.cpp:115:8:115:13 | buffer | | +| format.cpp:119:10:119:11 | 0 | format.cpp:120:29:120:29 | i | | +| format.cpp:119:10:119:11 | 0 | format.cpp:121:8:121:8 | i | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:120:29:120:29 | i [inner post update] | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:121:8:121:8 | i | | +| format.cpp:120:29:120:29 | i | format.cpp:120:28:120:29 | & ... | | +| format.cpp:124:10:124:11 | 0 | format.cpp:125:40:125:40 | i | | +| format.cpp:124:10:124:11 | 0 | format.cpp:126:8:126:8 | i | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:125:40:125:40 | i [inner post update] | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:126:8:126:8 | i | | +| format.cpp:125:40:125:40 | i | format.cpp:125:39:125:40 | & ... | | +| format.cpp:129:21:129:24 | {...} | format.cpp:130:32:130:37 | buffer | | +| format.cpp:129:21:129:24 | {...} | format.cpp:131:8:131:13 | buffer | | +| format.cpp:129:23:129:23 | 0 | format.cpp:129:21:129:24 | {...} | TAINT | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:130:32:130:37 | buffer [inner post update] | | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:131:8:131:13 | buffer | | +| format.cpp:130:32:130:37 | buffer | format.cpp:130:31:130:37 | & ... | | +| format.cpp:134:21:134:24 | {...} | format.cpp:135:40:135:45 | buffer | | +| format.cpp:134:21:134:24 | {...} | format.cpp:136:8:136:13 | buffer | | +| format.cpp:134:23:134:23 | 0 | format.cpp:134:21:134:24 | {...} | TAINT | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:135:40:135:45 | buffer [inner post update] | | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:136:8:136:13 | buffer | | +| format.cpp:135:40:135:45 | buffer | format.cpp:135:39:135:45 | & ... | | +| format.cpp:147:12:147:25 | call to source | format.cpp:151:14:151:14 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:154:13:154:13 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:157:7:157:7 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:157:16:157:16 | s | | +| format.cpp:148:16:148:30 | call to source | format.cpp:152:14:152:15 | ws | | +| format.cpp:148:16:148:30 | call to source | format.cpp:158:7:158:8 | ws | | +| format.cpp:148:16:148:30 | call to source | format.cpp:158:20:158:21 | ws | | +| format.cpp:154:6:154:11 | call to strlen | format.cpp:154:6:154:18 | ... + ... | TAINT | +| format.cpp:154:6:154:18 | ... + ... | format.cpp:154:2:154:18 | ... = ... | | +| format.cpp:154:6:154:18 | ... + ... | format.cpp:155:7:155:7 | i | | +| format.cpp:154:18:154:18 | 1 | format.cpp:154:6:154:18 | ... + ... | TAINT | +| format.cpp:157:7:157:7 | s | format.cpp:157:7:157:22 | access to array | TAINT | +| format.cpp:157:9:157:14 | call to strlen | format.cpp:157:9:157:21 | ... - ... | TAINT | +| format.cpp:157:9:157:21 | ... - ... | format.cpp:157:7:157:22 | access to array | TAINT | +| format.cpp:157:21:157:21 | 1 | format.cpp:157:9:157:21 | ... - ... | TAINT | +| format.cpp:158:7:158:8 | ws | format.cpp:158:7:158:27 | ... + ... | TAINT | +| format.cpp:158:7:158:27 | ref arg ... + ... | format.cpp:158:7:158:8 | ws [inner post update] | | +| format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | +| format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | +| format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | +| movableclass.cpp:8:2:8:15 | this | movableclass.cpp:8:27:8:31 | constructor init of field v [pre-this] | | +| movableclass.cpp:8:21:8:22 | _v | movableclass.cpp:8:29:8:30 | _v | | +| movableclass.cpp:8:29:8:30 | _v | movableclass.cpp:8:27:8:31 | constructor init of field v | TAINT | +| movableclass.cpp:9:2:9:15 | this | movableclass.cpp:10:3:10:3 | this | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:10:7:10:11 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:11:3:11:7 | other | | +| movableclass.cpp:10:13:10:13 | v | movableclass.cpp:10:3:10:13 | ... = ... | | +| movableclass.cpp:11:3:11:7 | other [post update] | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:11:13:11:13 | 0 | movableclass.cpp:11:3:11:13 | ... = ... | | +| movableclass.cpp:13:18:13:26 | this | movableclass.cpp:14:3:14:3 | this | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:14:7:14:11 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:15:3:15:7 | other | | +| movableclass.cpp:14:3:14:3 | this | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:3:14:3 | this [post update] | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:13:14:13 | v | movableclass.cpp:14:3:14:13 | ... = ... | | +| movableclass.cpp:15:3:15:7 | other [post update] | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:15:13:15:13 | 0 | movableclass.cpp:15:3:15:13 | ... = ... | | +| movableclass.cpp:16:11:16:14 | this | movableclass.cpp:16:10:16:14 | * ... | TAINT | +| movableclass.cpp:22:57:22:57 | 1 | movableclass.cpp:22:42:22:58 | call to MyMovableClass | TAINT | +| movableclass.cpp:23:55:23:60 | call to source | movableclass.cpp:23:40:23:63 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:21 | 1 | movableclass.cpp:28:21:28:22 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:22 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s1 | | +| movableclass.cpp:29:22:29:23 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s2 | | +| movableclass.cpp:29:23:29:23 | 1 | movableclass.cpp:29:22:29:23 | call to MyMovableClass | TAINT | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | s3 | | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:3:31:4 | ref arg s3 | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:8:31:8 | 1 | movableclass.cpp:31:8:31:8 | call to MyMovableClass | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | ref arg s3 | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:6:31:6 | call to operator= | TAINT | +| movableclass.cpp:39:21:39:26 | call to source | movableclass.cpp:39:21:39:29 | call to MyMovableClass | TAINT | +| movableclass.cpp:39:21:39:29 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s1 | | +| movableclass.cpp:40:22:40:30 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s2 | | +| movableclass.cpp:40:23:40:28 | call to source | movableclass.cpp:40:22:40:30 | call to MyMovableClass | TAINT | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | s3 | | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:3:42:4 | ref arg s3 | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:8:42:13 | call to source | movableclass.cpp:42:8:42:15 | call to MyMovableClass | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | ref arg s3 | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:6:42:6 | call to operator= | TAINT | +| movableclass.cpp:50:22:50:46 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s1 | | +| movableclass.cpp:50:38:50:43 | call to source | movableclass.cpp:50:22:50:46 | call to MyMovableClass | TAINT | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | s2 | | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:3:52:4 | ref arg s2 | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | ref arg s2 | TAINT | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:6:52:6 | call to operator= | TAINT | +| movableclass.cpp:52:23:52:28 | call to source | movableclass.cpp:52:8:52:31 | call to MyMovableClass | TAINT | +| movableclass.cpp:59:21:59:32 | call to getUnTainted | movableclass.cpp:59:21:59:35 | call to MyMovableClass | | +| movableclass.cpp:59:21:59:35 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s1 | | +| movableclass.cpp:60:21:60:30 | call to getTainted | movableclass.cpp:60:21:60:33 | call to MyMovableClass | | +| movableclass.cpp:60:21:60:33 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s2 | | +| movableclass.cpp:61:18:61:19 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | s3 | | +| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | @@ -148,10 +349,10 @@ | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:108:7:108:9 | ss1 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:110:7:110:9 | ss1 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:109:7:109:9 | ss2 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:111:7:111:9 | ss2 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | | stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | | stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | | stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | @@ -162,6 +363,401 @@ | stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | | +| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | | +| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT | +| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | | +| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | | +| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT | +| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | | +| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | | +| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT | +| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | | +| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | | +| stl.cpp:163:18:163:24 | hello | stl.cpp:163:18:163:25 | call to basic_string | TAINT | +| stl.cpp:163:18:163:25 | call to basic_string | stl.cpp:168:8:168:9 | s1 | | +| stl.cpp:164:19:164:26 | call to basic_string | stl.cpp:169:8:169:9 | s2 | | +| stl.cpp:164:20:164:26 | hello | stl.cpp:164:19:164:26 | call to basic_string | TAINT | +| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:166:3:166:14 | ... = ... | | +| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:170:8:170:9 | s3 | | +| stl.cpp:166:8:166:14 | hello | stl.cpp:166:8:166:14 | call to basic_string | TAINT | +| stl.cpp:174:18:174:23 | call to source | stl.cpp:174:18:174:26 | call to basic_string | TAINT | +| stl.cpp:174:18:174:26 | call to basic_string | stl.cpp:179:8:179:9 | s1 | | +| stl.cpp:175:19:175:27 | call to basic_string | stl.cpp:180:8:180:9 | s2 | | +| stl.cpp:175:20:175:25 | call to source | stl.cpp:175:19:175:27 | call to basic_string | TAINT | +| stl.cpp:177:8:177:13 | call to source | stl.cpp:177:8:177:15 | call to basic_string | TAINT | +| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:177:3:177:15 | ... = ... | | +| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:181:8:181:9 | s3 | | +| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:186:20:186:21 | s1 | | +| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:188:8:188:9 | s1 | | +| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:190:8:190:9 | s1 | | +| stl.cpp:186:20:186:21 | s1 | stl.cpp:191:8:191:9 | s2 | | +| stl.cpp:188:8:188:9 | s1 | stl.cpp:188:3:188:9 | ... = ... | | +| stl.cpp:188:8:188:9 | s1 | stl.cpp:192:8:192:9 | s3 | | +| stl.cpp:196:19:196:40 | call to basic_string | stl.cpp:200:8:200:9 | s1 | | +| stl.cpp:196:32:196:37 | call to source | stl.cpp:196:19:196:40 | call to basic_string | TAINT | +| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:198:3:198:28 | ... = ... | | +| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:201:8:201:9 | s2 | | +| stl.cpp:198:20:198:25 | call to source | stl.cpp:198:8:198:28 | call to basic_string | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | | +| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| structlikeclass.cpp:16:22:16:22 | 1 | structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:18:22:18:23 | s1 | | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s1 | | +| structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | structlikeclass.cpp:23:8:23:9 | s2 | | +| structlikeclass.cpp:17:24:17:24 | 1 | structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:18:22:18:23 | s1 | structlikeclass.cpp:24:8:24:9 | s3 | | +| structlikeclass.cpp:20:8:20:8 | 1 | structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:20:3:20:8 | ... = ... | | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:25:8:25:9 | s4 | | +| structlikeclass.cpp:29:22:29:27 | call to source | structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:31:22:31:23 | s1 | | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s1 | | +| structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | structlikeclass.cpp:36:8:36:9 | s2 | | +| structlikeclass.cpp:30:24:30:29 | call to source | structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:31:22:31:23 | s1 | structlikeclass.cpp:37:8:37:9 | s3 | | +| structlikeclass.cpp:33:8:33:13 | call to source | structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:33:3:33:15 | ... = ... | | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:38:8:38:9 | s4 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:43:24:43:25 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:44:22:44:23 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:46:8:46:9 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:48:8:48:9 | s1 | | +| structlikeclass.cpp:43:24:43:25 | s1 | structlikeclass.cpp:49:8:49:9 | s2 | | +| structlikeclass.cpp:44:22:44:23 | s1 | structlikeclass.cpp:50:8:50:9 | s3 | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:46:3:46:9 | ... = ... | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:51:8:51:9 | s4 | | +| structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s1 | | +| structlikeclass.cpp:55:40:55:45 | call to source | structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:58:3:58:32 | ... = ... | | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:61:8:61:9 | s2 | | +| structlikeclass.cpp:58:24:58:29 | call to source | structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:13:62:18 | call to source | structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | structlikeclass.cpp:62:8:62:20 | ... = ... | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:24:9:24:13 | this | swap1.cpp:24:31:24:34 | this | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:36:24:39 | that | | +| swap1.cpp:24:36:24:39 | ref arg that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:25:9:25:13 | this | swap1.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap1.cpp:25:28:25:31 | that | swap1.cpp:25:42:25:45 | that | | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:47:25:51 | data1 | | +| swap1.cpp:27:16:27:24 | this | swap1.cpp:30:13:30:16 | this | | +| swap1.cpp:27:39:27:42 | that | swap1.cpp:29:24:29:27 | that | | +| swap1.cpp:29:23:29:27 | call to Class | swap1.cpp:30:18:30:20 | tmp | | +| swap1.cpp:29:24:29:27 | that | swap1.cpp:29:23:29:27 | call to Class | | +| swap1.cpp:30:13:30:16 | ref arg this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:30:13:30:16 | this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:31:21:31:24 | this | swap1.cpp:31:20:31:24 | * ... | TAINT | +| swap1.cpp:34:16:34:24 | this | swap1.cpp:36:13:36:16 | this | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:36:18:36:21 | that | | +| swap1.cpp:36:13:36:16 | ref arg this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:13:36:16 | this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:18:36:21 | ref arg that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:37:21:37:24 | this | swap1.cpp:37:20:37:24 | * ... | TAINT | +| swap1.cpp:40:16:40:26 | this | swap1.cpp:43:13:43:16 | this | | +| swap1.cpp:40:41:40:44 | that | swap1.cpp:42:24:42:27 | that | | +| swap1.cpp:42:23:42:27 | call to Class | swap1.cpp:43:18:43:20 | tmp | | +| swap1.cpp:42:24:42:27 | that | swap1.cpp:42:23:42:27 | call to Class | | +| swap1.cpp:43:13:43:16 | ref arg this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:43:13:43:16 | this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:44:21:44:24 | this | swap1.cpp:44:20:44:24 | * ... | TAINT | +| swap1.cpp:47:16:47:26 | this | swap1.cpp:49:13:49:16 | this | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:49:18:49:21 | that | | +| swap1.cpp:49:13:49:16 | ref arg this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:13:49:16 | this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:18:49:21 | ref arg that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:50:21:50:24 | this | swap1.cpp:50:20:50:24 | * ... | TAINT | +| swap1.cpp:53:14:53:17 | this | swap1.cpp:56:18:56:22 | this | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:56:25:56:28 | that | | +| swap1.cpp:56:18:56:22 | data1 | swap1.cpp:56:30:56:34 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that [post update] | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:56:30:56:34 | data1 | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap1.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:71:5:71:5 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:74:10:74:10 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:76:5:76:5 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:73:12:73:16 | data1 | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:79:12:79:16 | data1 | | +| swap1.cpp:71:15:71:20 | call to source | swap1.cpp:71:5:71:22 | ... = ... | | +| swap1.cpp:76:5:76:5 | ref arg y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:5:76:5 | ref arg y | TAINT | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:7:76:7 | call to operator= | TAINT | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:82:5:82:6 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:85:14:85:15 | z2 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:83:13:83:17 | data1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:88:13:88:17 | data1 | | +| swap1.cpp:82:16:82:21 | call to source | swap1.cpp:82:5:82:23 | ... = ... | | +| swap1.cpp:85:10:85:11 | ref arg z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:85:14:85:15 | ref arg z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:95:5:95:5 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:98:10:98:10 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:100:5:100:5 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:97:12:97:16 | data1 | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:103:12:103:16 | data1 | | +| swap1.cpp:95:15:95:20 | call to source | swap1.cpp:95:5:95:22 | ... = ... | | +| swap1.cpp:100:5:100:5 | ref arg y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:100:19:100:19 | x [inner post update] | | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:9:100:17 | call to move | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:109:5:109:13 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:111:20:111:24 | data1 | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:115:18:115:22 | data1 | | +| swap1.cpp:109:23:109:28 | call to source | swap1.cpp:109:5:109:30 | ... = ... | | +| swap1.cpp:113:31:113:39 | call to move | swap1.cpp:113:31:113:51 | call to Class | | +| swap1.cpp:113:31:113:39 | ref arg call to move | swap1.cpp:113:41:113:49 | move_from [inner post update] | | +| swap1.cpp:113:31:113:51 | call to Class | swap1.cpp:115:10:115:16 | move_to | | +| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:122:5:122:5 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:125:10:125:10 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:127:5:127:5 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:124:12:124:16 | data1 | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:130:12:130:16 | data1 | | +| swap1.cpp:122:15:122:20 | call to source | swap1.cpp:122:5:122:22 | ... = ... | | +| swap1.cpp:127:5:127:5 | ref arg y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:137:5:137:5 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:140:10:140:10 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:142:5:142:5 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:139:12:139:16 | data1 | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:145:12:145:16 | data1 | | +| swap1.cpp:137:15:137:20 | call to source | swap1.cpp:137:5:137:22 | ... = ... | | +| swap1.cpp:142:5:142:5 | ref arg y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:142:29:142:29 | x [inner post update] | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:142:29:142:29 | x | swap1.cpp:142:19:142:27 | call to move | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:24:9:24:13 | this | swap2.cpp:24:31:24:34 | this | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:36:24:39 | that | | +| swap2.cpp:24:36:24:39 | ref arg that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:25:9:25:13 | this | swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:42:25:45 | that | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:61:25:64 | that | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [post-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:47:25:51 | data1 | | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:55:25:71 | constructor init of field data2 | TAINT | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:66:25:70 | data2 | | +| swap2.cpp:27:16:27:24 | this | swap2.cpp:30:13:30:16 | this | | +| swap2.cpp:27:39:27:42 | that | swap2.cpp:29:24:29:27 | that | | +| swap2.cpp:29:23:29:27 | call to Class | swap2.cpp:30:18:30:20 | tmp | | +| swap2.cpp:29:24:29:27 | that | swap2.cpp:29:23:29:27 | call to Class | | +| swap2.cpp:30:13:30:16 | ref arg this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:30:13:30:16 | this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:31:21:31:24 | this | swap2.cpp:31:20:31:24 | * ... | TAINT | +| swap2.cpp:34:16:34:24 | this | swap2.cpp:36:13:36:16 | this | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:36:18:36:21 | that | | +| swap2.cpp:36:13:36:16 | ref arg this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:13:36:16 | this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:18:36:21 | ref arg that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:37:21:37:24 | this | swap2.cpp:37:20:37:24 | * ... | TAINT | +| swap2.cpp:40:16:40:26 | this | swap2.cpp:43:13:43:16 | this | | +| swap2.cpp:40:41:40:44 | that | swap2.cpp:42:24:42:27 | that | | +| swap2.cpp:42:23:42:27 | call to Class | swap2.cpp:43:18:43:20 | tmp | | +| swap2.cpp:42:24:42:27 | that | swap2.cpp:42:23:42:27 | call to Class | | +| swap2.cpp:43:13:43:16 | ref arg this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:43:13:43:16 | this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:44:21:44:24 | this | swap2.cpp:44:20:44:24 | * ... | TAINT | +| swap2.cpp:47:16:47:26 | this | swap2.cpp:49:13:49:16 | this | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:49:18:49:21 | that | | +| swap2.cpp:49:13:49:16 | ref arg this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:13:49:16 | this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:18:49:21 | ref arg that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:50:21:50:24 | this | swap2.cpp:50:20:50:24 | * ... | TAINT | +| swap2.cpp:53:14:53:17 | this | swap2.cpp:56:18:56:22 | this | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:25:56:28 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:18:56:22 | data1 | swap2.cpp:56:30:56:34 | ref arg data1 | | +| swap2.cpp:56:18:56:22 | this | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:18:56:22 | this [post update] | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:25:56:28 | that | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:30:56:34 | data1 | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:43:56:47 | data2 | swap2.cpp:56:55:56:59 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:55:56:59 | data2 | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap2.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:71:5:71:5 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:74:10:74:10 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:76:5:76:5 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:73:12:73:16 | data1 | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:79:12:79:16 | data1 | | +| swap2.cpp:71:15:71:20 | call to source | swap2.cpp:71:5:71:22 | ... = ... | | +| swap2.cpp:76:5:76:5 | ref arg y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:5:76:5 | ref arg y | TAINT | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:7:76:7 | call to operator= | TAINT | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:82:5:82:6 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:85:14:85:15 | z2 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:83:13:83:17 | data1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:88:13:88:17 | data1 | | +| swap2.cpp:82:16:82:21 | call to source | swap2.cpp:82:5:82:23 | ... = ... | | +| swap2.cpp:85:10:85:11 | ref arg z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:85:14:85:15 | ref arg z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:95:5:95:5 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:98:10:98:10 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:100:5:100:5 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:97:12:97:16 | data1 | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:103:12:103:16 | data1 | | +| swap2.cpp:95:15:95:20 | call to source | swap2.cpp:95:5:95:22 | ... = ... | | +| swap2.cpp:100:5:100:5 | ref arg y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:100:19:100:19 | x [inner post update] | | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:9:100:17 | call to move | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:109:5:109:13 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:111:20:111:24 | data1 | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:115:18:115:22 | data1 | | +| swap2.cpp:109:23:109:28 | call to source | swap2.cpp:109:5:109:30 | ... = ... | | +| swap2.cpp:113:31:113:39 | call to move | swap2.cpp:113:31:113:51 | call to Class | | +| swap2.cpp:113:31:113:39 | ref arg call to move | swap2.cpp:113:41:113:49 | move_from [inner post update] | | +| swap2.cpp:113:31:113:51 | call to Class | swap2.cpp:115:10:115:16 | move_to | | +| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:122:5:122:5 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:125:10:125:10 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:127:5:127:5 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:124:12:124:16 | data1 | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:130:12:130:16 | data1 | | +| swap2.cpp:122:15:122:20 | call to source | swap2.cpp:122:5:122:22 | ... = ... | | +| swap2.cpp:127:5:127:5 | ref arg y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:137:5:137:5 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:140:10:140:10 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:142:5:142:5 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:139:12:139:16 | data1 | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:145:12:145:16 | data1 | | +| swap2.cpp:137:15:137:20 | call to source | swap2.cpp:137:5:137:22 | ... = ... | | +| swap2.cpp:142:5:142:5 | ref arg y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:142:29:142:29 | x [inner post update] | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:142:29:142:29 | x | swap2.cpp:142:19:142:27 | call to move | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | @@ -226,10 +822,10 @@ | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:93:7:93:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:94:7:94:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:95:7:95:9 | mc2 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:88:7:88:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:89:7:89:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:90:7:90:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:91:7:91:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:88:7:88:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:89:7:89:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:90:7:90:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:91:7:91:9 | mc1 | | | taint.cpp:100:21:100:21 | i | taint.cpp:106:7:106:7 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:110:12:110:12 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:112:12:112:12 | i | | @@ -313,11 +909,13 @@ | taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | | | taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT | | taint.cpp:185:11:185:16 | call to source | taint.cpp:186:11:186:11 | x | | +| taint.cpp:186:10:186:11 | ref arg & ... | taint.cpp:186:11:186:11 | x [inner post update] | | | taint.cpp:186:11:186:11 | x | taint.cpp:186:10:186:11 | & ... | | | taint.cpp:192:23:192:28 | source | taint.cpp:194:13:194:18 | source | | | taint.cpp:193:6:193:6 | x | taint.cpp:194:10:194:10 | x | | | taint.cpp:193:6:193:6 | x | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:9:194:10 | & ... | taint.cpp:194:2:194:7 | call to memcpy | | +| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:10:194:10 | x [inner post update] | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | | | taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT | @@ -359,7 +957,7 @@ | taint.cpp:228:11:228:11 | this | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | | | taint.cpp:228:17:228:17 | this | taint.cpp:229:3:229:6 | this | | | taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | | -| taint.cpp:230:3:230:6 | this | taint.cpp:231:3:231:11 | this | | +| taint.cpp:230:3:230:6 | this | file://:0:0:0:0 | this | | | taint.cpp:235:10:239:2 | [...](...){...} | taint.cpp:240:2:240:2 | b | | | taint.cpp:235:10:239:2 | {...} | taint.cpp:235:10:239:2 | [...](...){...} | | | taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT | @@ -477,8 +1075,10 @@ | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:348:17:348:17 | t | | | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:345:12:345:12 | ref arg b | taint.cpp:352:7:352:7 | b | | +| taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:346:13:346:13 | c [inner post update] | | | taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:353:7:353:7 | c | | | taint.cpp:346:13:346:13 | c | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:347:13:347:13 | d [inner post update] | | | taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:354:7:354:7 | d | | | taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | | | taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | | @@ -507,31 +1107,34 @@ | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:390:2:390:28 | ... = ... | | | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | | | taint.cpp:390:13:390:27 | hello, world | taint.cpp:390:6:390:11 | call to wcsdup | TAINT | +| taint.cpp:417:13:417:13 | 0 | taint.cpp:417:13:417:14 | call to MyClass2 | TAINT | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:420:7:420:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:421:7:421:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:422:2:422:2 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:423:7:423:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:424:7:424:7 | a | | +| taint.cpp:417:19:417:19 | 0 | taint.cpp:417:19:417:20 | call to MyClass2 | TAINT | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:426:7:426:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:427:7:427:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:428:2:428:2 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:429:7:429:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:430:7:430:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:431:7:431:7 | b | | +| taint.cpp:418:13:418:14 | | taint.cpp:418:13:418:15 | call to MyClass3 | TAINT | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:443:7:443:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:444:7:444:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:446:7:446:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:447:7:447:7 | d | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:422:2:422:2 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:428:2:428:2 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:429:7:429:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:430:7:430:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:431:7:431:7 | b | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:422:2:422:2 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:428:2:428:2 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:429:7:429:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:430:7:430:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:431:7:431:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | | @@ -545,27 +1148,28 @@ | taint.cpp:433:6:433:20 | new | taint.cpp:438:7:438:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:439:7:439:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:441:9:441:9 | c | | +| taint.cpp:433:19:433:19 | 0 | taint.cpp:433:6:433:20 | call to MyClass2 | TAINT | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:436:7:436:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:437:2:437:2 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:437:2:437:2 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:441:9:441:9 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:437:2:437:2 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:441:9:441:9 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:439:7:439:7 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:439:7:439:7 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:441:9:441:9 | c | taint.cpp:441:2:441:9 | delete | TAINT | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:445:2:445:2 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:447:7:447:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:447:7:447:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:445:2:445:2 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:447:7:447:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:447:7:447:7 | d | | | taint.cpp:452:16:452:16 | a | taint.cpp:454:10:454:10 | a | | | taint.cpp:452:24:452:24 | b | taint.cpp:455:6:455:6 | b | | | taint.cpp:454:10:454:10 | a | taint.cpp:456:6:456:6 | c | | @@ -583,3 +1187,13 @@ | taint.cpp:463:6:463:6 | 0 | taint.cpp:471:7:471:7 | y | | | taint.cpp:468:7:468:7 | ref arg x | taint.cpp:470:7:470:7 | x | | | taint.cpp:468:10:468:10 | ref arg y | taint.cpp:471:7:471:7 | y | | +| taint.cpp:480:26:480:32 | source1 | taint.cpp:483:28:483:34 | source1 | | +| taint.cpp:481:15:481:21 | 0 | taint.cpp:483:12:483:15 | line | | +| taint.cpp:481:15:481:21 | 0 | taint.cpp:485:7:485:10 | line | | +| taint.cpp:482:9:482:9 | n | taint.cpp:483:19:483:19 | n | | +| taint.cpp:483:11:483:15 | ref arg & ... | taint.cpp:483:12:483:15 | line [inner post update] | | +| taint.cpp:483:11:483:15 | ref arg & ... | taint.cpp:485:7:485:10 | line | | +| taint.cpp:483:12:483:15 | line | taint.cpp:483:11:483:15 | & ... | | +| taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | +| taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | +| taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp new file mode 100644 index 00000000000..c0003388307 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -0,0 +1,67 @@ + +int source(); +void sink(...) {}; + +class MyMovableClass { +public: + MyMovableClass() {} // Constructor + MyMovableClass(int _v) : v(_v) {} // ConversionConstructor + MyMovableClass(MyMovableClass &&other) noexcept { // ConversionConstructor, MoveConstructor + v = other.v; + other.v = 0; + } + MyMovableClass &operator=(MyMovableClass &&other) noexcept { // MoveAssignmentOperator + v = other.v; + other.v = 0; + return *this; + } + + int v; +}; + +MyMovableClass &&getUnTainted() { return MyMovableClass(1); } +MyMovableClass &&getTainted() { return MyMovableClass(source()); } + +void test_copyableclass() +{ + { + MyMovableClass s1(1); + MyMovableClass s2 = 1; + MyMovableClass s3; + s3 = 1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + MyMovableClass s1(source()); + MyMovableClass s2 = source(); + MyMovableClass s3; + s3 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + } + + { + MyMovableClass s1 = MyMovableClass(source()); + MyMovableClass s2; + s2 = MyMovableClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + } + + { + MyMovableClass s1(getUnTainted()); + MyMovableClass s2(getTainted()); + MyMovableClass s3; + + sink(s1); + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp index d92bb39d158..cf45d5b90eb 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp @@ -131,3 +131,74 @@ void test_strings2() string path3(user_input()); sink(path3.c_str(), "r"); // tainted } + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted + sink(ss); // tainted +} + +void test_string_constructors_assignments() +{ + { + std::string s1("hello"); + std::string s2 = "hello"; + std::string s3; + s3 = "hello"; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1(source()); + std::string s2 = source(); + std::string s3; + s3 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + } + + { + std::string s1; + std::string s2 = s1; + std::string s3; + s3 = s1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1 = std::string(source()); + std::string s2; + s2 = std::string(source()); + + sink(s1); // tainted + sink(s2); // tainted + } +} + diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp new file mode 100644 index 00000000000..727a0fff53b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp @@ -0,0 +1,64 @@ + +int source(); +void sink(...) {}; + +class StructLikeClass { +public: + StructLikeClass() {} // Constructor + StructLikeClass(int _v) : v(_v) {} // ConversionConstructor + + int v; +}; + +void test_structlikeclass() +{ + { + StructLikeClass s1(1); + StructLikeClass s2 = 1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1(source()); + StructLikeClass s2 = source(); + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + StructLikeClass s1; + StructLikeClass s2 = s1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1 = StructLikeClass(source()); + StructLikeClass s2; + StructLikeClass s3; + s2 = StructLikeClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h new file mode 100644 index 00000000000..6e554ac15db --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h @@ -0,0 +1,5 @@ +namespace std +{ + template + constexpr void swap(T &a, T &b); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp new file mode 100644 index 00000000000..7ba05b86f72 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -0,0 +1,146 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template + T &&move(T &t) noexcept { return static_cast(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted +} + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp new file mode 100644 index 00000000000..e5203f344f2 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -0,0 +1,146 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template + T &&move(T &t) noexcept { return static_cast(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; int data2; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1), data2(that.data2) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); swap(data2, that.data2); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted +} + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 5d8327017fa..834ac0c84b2 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -86,12 +86,12 @@ void class_field_test() { mc1.myMethod(); sink(mc1.a); - sink(mc1.b); // tainted [NOT DETECTED with IR] - sink(mc1.c); // tainted [NOT DETECTED with IR] - sink(mc1.d); // tainted [NOT DETECTED with IR] + sink(mc1.b); // tainted + sink(mc1.c); // tainted + sink(mc1.d); // tainted sink(mc2.a); - sink(mc2.b); // tainted [NOT DETECTED with IR] - sink(mc2.c); // tainted [NOT DETECTED with IR] + sink(mc2.b); // tainted + sink(mc2.c); // tainted sink(mc2.d); } @@ -197,9 +197,9 @@ void test_memcpy(int *source) { // --- std::swap --- -namespace std { - template constexpr void swap(T& a, T& b); -} +#include "swap.h" + + void test_swap() { int x, y; @@ -470,3 +470,17 @@ void test_swop() { sink(x); // clean [FALSE POSITIVE] sink(y); // tainted } + +// --- getdelim --- + +struct FILE; + +int getdelim(char ** lineptr, size_t * n, int delimiter, FILE *stream); + +void test_getdelim(FILE* source1) { + char* line = nullptr; + size_t n; + getdelim(&line, &n, '\n', source1); + + sink(line); +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 59193d81722..61ff7941b68 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,19 +1,103 @@ -| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source | -| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source | -| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source | -| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source | -| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source | -| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source | -| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source | -| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source | -| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source | -| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source | +| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source | +| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:43:8:43:9 | s4 | copyableclass.cpp:38:8:38:13 | call to source | +| copyableclass.cpp:65:8:65:9 | s1 | copyableclass.cpp:60:40:60:45 | call to source | +| copyableclass.cpp:66:8:66:9 | s2 | copyableclass.cpp:63:24:63:29 | call to source | +| copyableclass.cpp:67:11:67:11 | call to operator= | copyableclass.cpp:67:13:67:18 | call to source | +| copyableclass_declonly.cpp:40:8:40:9 | s1 | copyableclass_declonly.cpp:34:30:34:35 | call to source | +| copyableclass_declonly.cpp:41:8:41:9 | s2 | copyableclass_declonly.cpp:35:32:35:37 | call to source | +| copyableclass_declonly.cpp:42:8:42:9 | s3 | copyableclass_declonly.cpp:34:30:34:35 | call to source | +| copyableclass_declonly.cpp:43:8:43:9 | s4 | copyableclass_declonly.cpp:38:8:38:13 | call to source | +| copyableclass_declonly.cpp:65:8:65:9 | s1 | copyableclass_declonly.cpp:60:56:60:61 | call to source | +| copyableclass_declonly.cpp:66:8:66:9 | s2 | copyableclass_declonly.cpp:63:32:63:37 | call to source | +| copyableclass_declonly.cpp:67:11:67:11 | call to operator= | copyableclass_declonly.cpp:67:13:67:18 | call to source | +| format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | +| format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | +| format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | +| format.cpp:72:8:72:13 | buffer | format.cpp:71:42:71:55 | call to source | +| format.cpp:83:8:83:13 | buffer | format.cpp:82:36:82:41 | call to source | +| format.cpp:88:8:88:13 | buffer | format.cpp:87:38:87:43 | call to source | +| format.cpp:94:8:94:13 | buffer | format.cpp:93:36:93:49 | call to source | +| format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | +| format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | +| format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | +| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | +| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | +| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source | +| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source | +| movableclass.cpp:46:8:46:9 | s3 | movableclass.cpp:42:8:42:13 | call to source | +| movableclass.cpp:54:8:54:9 | s1 | movableclass.cpp:50:38:50:43 | call to source | +| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source | +| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source | +| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | | stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source | +| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | call to source | +| stl.cpp:179:8:179:9 | s1 | stl.cpp:174:18:174:23 | call to source | +| stl.cpp:180:8:180:9 | s2 | stl.cpp:175:20:175:25 | call to source | +| stl.cpp:181:8:181:9 | s3 | stl.cpp:177:8:177:13 | call to source | +| stl.cpp:200:8:200:9 | s1 | stl.cpp:196:32:196:37 | call to source | +| stl.cpp:201:8:201:9 | s2 | stl.cpp:198:20:198:25 | call to source | +| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source | +| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source | +| structlikeclass.cpp:60:8:60:9 | s1 | structlikeclass.cpp:55:40:55:45 | call to source | +| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source | +| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source | +| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:69:23:69:23 | x | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:87:13:87:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:81:27:81:28 | z2 | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:93:23:93:23 | x | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:103:12:103:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:111:20:111:24 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:108:23:108:31 | move_from | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:124:12:124:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:120:23:120:23 | x | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:130:12:130:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:139:12:139:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:135:23:135:23 | x | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:145:12:145:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap2.cpp:73:12:73:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:69:23:69:23 | x | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:81:27:81:28 | z2 | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:93:23:93:23 | x | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:103:12:103:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:111:20:111:24 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:108:23:108:31 | move_from | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:124:12:124:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:120:23:120:23 | x | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:130:12:130:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:139:12:139:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:135:23:135:23 | x | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:145:12:145:16 | data1 | swap2.cpp:137:15:137:20 | call to source | | taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | | taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source | | taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source | @@ -67,3 +151,4 @@ | taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source | | taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source | | taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source | +| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 58a7255accb..4c0aa6dc0d3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -1,26 +1,68 @@ -| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only | -| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only | -| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only | -| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only | -| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only | -| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only | -| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only | -| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only | -| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only | -| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only | +| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only | +| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only | +| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only | +| copyableclass.cpp:43:8:43:9 | copyableclass.cpp:38:8:38:13 | AST only | +| copyableclass.cpp:65:8:65:9 | copyableclass.cpp:60:40:60:45 | AST only | +| copyableclass.cpp:66:8:66:9 | copyableclass.cpp:63:24:63:29 | AST only | +| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only | +| copyableclass_declonly.cpp:40:8:40:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only | +| copyableclass_declonly.cpp:41:8:41:9 | copyableclass_declonly.cpp:35:32:35:37 | AST only | +| copyableclass_declonly.cpp:42:8:42:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only | +| copyableclass_declonly.cpp:43:8:43:9 | copyableclass_declonly.cpp:38:8:38:13 | AST only | +| copyableclass_declonly.cpp:65:8:65:9 | copyableclass_declonly.cpp:60:56:60:61 | AST only | +| copyableclass_declonly.cpp:66:8:66:9 | copyableclass_declonly.cpp:63:32:63:37 | AST only | +| copyableclass_declonly.cpp:67:11:67:11 | copyableclass_declonly.cpp:67:13:67:18 | AST only | +| format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | +| format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | +| format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | +| format.cpp:72:8:72:13 | format.cpp:71:42:71:55 | AST only | +| format.cpp:83:8:83:13 | format.cpp:82:36:82:41 | AST only | +| format.cpp:88:8:88:13 | format.cpp:87:38:87:43 | AST only | +| format.cpp:94:8:94:13 | format.cpp:93:36:93:49 | AST only | +| format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | +| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | +| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | +| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:21:39:26 | AST only | +| movableclass.cpp:45:8:45:9 | movableclass.cpp:40:23:40:28 | AST only | +| movableclass.cpp:46:8:46:9 | movableclass.cpp:42:8:42:13 | AST only | +| movableclass.cpp:54:8:54:9 | movableclass.cpp:50:38:50:43 | AST only | +| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only | +| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only | +| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only | | stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only | +| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only | +| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only | +| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | AST only | +| stl.cpp:179:8:179:9 | stl.cpp:174:18:174:23 | AST only | +| stl.cpp:180:8:180:9 | stl.cpp:175:20:175:25 | AST only | +| stl.cpp:181:8:181:9 | stl.cpp:177:8:177:13 | AST only | +| stl.cpp:200:8:200:9 | stl.cpp:196:32:196:37 | AST only | +| stl.cpp:201:8:201:9 | stl.cpp:198:20:198:25 | AST only | +| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only | +| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only | +| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only | +| structlikeclass.cpp:60:8:60:9 | structlikeclass.cpp:55:40:55:45 | AST only | +| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only | +| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only | +| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only | +| swap1.cpp:102:12:102:16 | swap1.cpp:93:23:93:23 | AST only | +| swap1.cpp:115:18:115:22 | swap1.cpp:108:23:108:31 | AST only | +| swap1.cpp:129:12:129:16 | swap1.cpp:120:23:120:23 | AST only | +| swap1.cpp:144:12:144:16 | swap1.cpp:135:23:135:23 | AST only | +| swap2.cpp:78:12:78:16 | swap2.cpp:69:23:69:23 | AST only | +| swap2.cpp:88:13:88:17 | swap2.cpp:81:27:81:28 | AST only | +| swap2.cpp:102:12:102:16 | swap2.cpp:93:23:93:23 | AST only | +| swap2.cpp:115:18:115:22 | swap2.cpp:108:23:108:31 | AST only | +| swap2.cpp:129:12:129:16 | swap2.cpp:120:23:120:23 | AST only | +| swap2.cpp:144:12:144:16 | swap2.cpp:135:23:135:23 | AST only | | taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only | | taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only | | taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only | -| taint.cpp:89:11:89:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:90:11:90:11 | taint.cpp:72:7:72:12 | AST only | -| taint.cpp:91:11:91:11 | taint.cpp:77:7:77:12 | AST only | -| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only | | taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only | | taint.cpp:110:7:110:13 | taint.cpp:105:12:105:17 | IR only | | taint.cpp:111:7:111:13 | taint.cpp:106:12:106:17 | IR only | @@ -28,14 +70,9 @@ | taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only | | taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | | taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only | -| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only | -| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only | | taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only | | taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index 3c94aab79db..0a9ab23c69a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -1,8 +1,53 @@ +| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source | +| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | +| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... | +| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source | +| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source | +| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source | +| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:103:12:103:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:111:20:111:24 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:124:12:124:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:130:12:130:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:139:12:139:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:145:12:145:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap2.cpp:73:12:73:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:103:12:103:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:111:20:111:24 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:124:12:124:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:130:12:130:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:139:12:139:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:145:12:145:16 | data1 | swap2.cpp:137:15:137:20 | call to source | | taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | | taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source | | taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source | +| taint.cpp:89:11:89:11 | b | taint.cpp:71:22:71:27 | call to source | +| taint.cpp:90:11:90:11 | c | taint.cpp:72:7:72:12 | call to source | +| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source | +| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source | +| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source | | taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source | | taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source | | taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source | @@ -13,10 +58,15 @@ | taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source | | taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source | | taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source | +| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source | | taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source | +| taint.cpp:229:3:229:6 | t | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:233:8:233:8 | call to operator() | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source | | taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source | | taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source | @@ -28,3 +78,4 @@ | taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source | | taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source | | taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source | +| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | diff --git a/cpp/ql/test/library-tests/defuse/addressOf.cpp b/cpp/ql/test/library-tests/defuse/addressOf.cpp index 6d6c1265b67..4954159c13d 100644 --- a/cpp/ql/test/library-tests/defuse/addressOf.cpp +++ b/cpp/ql/test/library-tests/defuse/addressOf.cpp @@ -63,3 +63,18 @@ void nonexamples(int *ptr, int &ref) { nonexamples(&*ptr, ref); } } + + +namespace std { + template + constexpr T *addressof(T &obj) noexcept { + return __builtin_addressof(obj); + } +} + +void use_std_addressof() { + int x = 0; + int *y = std::addressof(x) + *std::addressof(x); +} + +// semmle-extractor-options: --clang diff --git a/cpp/ql/test/library-tests/defuse/definition.expected b/cpp/ql/test/library-tests/defuse/definition.expected index 35d91efd916..cf7ff1942e2 100644 --- a/cpp/ql/test/library-tests/defuse/definition.expected +++ b/cpp/ql/test/library-tests/defuse/definition.expected @@ -17,6 +17,8 @@ | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:58:18:58:18 | a | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | diff --git a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected index 7c0e5bd3f8e..96389527265 100644 --- a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected @@ -12,6 +12,7 @@ | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:50:3:50:4 | f2 | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:57:19:57:19 | a | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | addressOf.cpp:58:18:58:18 | a | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:77:27:77:27 | x | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:26:5:26:5 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | indirect_use.cpp:27:17:27:17 | p | diff --git a/cpp/ql/test/library-tests/defuse/exprDefinition.expected b/cpp/ql/test/library-tests/defuse/exprDefinition.expected index ec45bd97f2b..c2431284bfa 100644 --- a/cpp/ql/test/library-tests/defuse/exprDefinition.expected +++ b/cpp/ql/test/library-tests/defuse/exprDefinition.expected @@ -1,6 +1,8 @@ | addressOf.cpp:47:8:47:9 | f1 | addressOf.cpp:47:12:47:31 | [...](...){...} | addressOf.cpp:47:12:47:31 | [...](...){...} | | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:49:12:49:39 | [...](...){...} | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:56:13:56:28 | {...} | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:35:10:35:10 | p | indirect_use.cpp:35:14:35:15 | ip | indirect_use.cpp:35:14:35:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected index 8a57ff7206e..c7a5adde333 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -11,8 +11,11 @@ | addressOf.cpp:38:20:38:20 | i | non-const address | | addressOf.cpp:40:15:40:15 | i | non-const address | | addressOf.cpp:42:19:42:22 | iref | non-const address | +| addressOf.cpp:47:12:47:31 | captured | non-const address | +| addressOf.cpp:47:19:47:28 | captured | | | addressOf.cpp:48:3:48:4 | f1 | const address | | addressOf.cpp:49:15:49:22 | captured | non-const address | +| addressOf.cpp:49:27:49:36 | captured | | | addressOf.cpp:50:3:50:4 | f2 | const address | | addressOf.cpp:51:10:51:17 | captured | | | addressOf.cpp:56:16:56:16 | i | | @@ -25,9 +28,10 @@ | addressOf.cpp:62:11:62:13 | ptr | | | addressOf.cpp:63:19:63:21 | ptr | | | addressOf.cpp:63:24:63:26 | ref | non-const address | -| file://:0:0:0:0 | captured | | -| file://:0:0:0:0 | captured | | -| file://:0:0:0:0 | captured | non-const address | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:77:27:77:27 | x | non-const address | +| addressOf.cpp:77:48:77:48 | x | | | indirect_use.cpp:17:32:17:43 | globalIntPtr | non-const address | | indirect_use.cpp:20:14:20:15 | ip | | | indirect_use.cpp:21:17:21:17 | p | | diff --git a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected index c2eff5fac12..5eb3d7d75c1 100644 --- a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected @@ -1,11 +1,13 @@ | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:32:19:32:19 | i | -| addressOf.cpp:46:17:46:24 | captured | file://:0:0:0:0 | captured | +| addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:47:12:47:31 | captured | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:16:56:16 | i | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:19:56:19 | i | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:24:56:24 | i | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | | indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp | diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.expected b/cpp/ql/test/library-tests/defuse/useOfVar.expected index 1efe7e5dac7..f1b2a0e6951 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVar.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVar.expected @@ -10,9 +10,9 @@ | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:38:20:38:20 | i | | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:40:15:40:15 | i | | addressOf.cpp:40:8:40:11 | iref | addressOf.cpp:42:19:42:22 | iref | +| addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:47:12:47:31 | captured | | addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:49:15:49:22 | captured | | addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:51:10:51:17 | captured | -| addressOf.cpp:46:17:46:24 | captured | file://:0:0:0:0 | captured | | addressOf.cpp:47:8:47:9 | f1 | addressOf.cpp:48:3:48:4 | f1 | | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:50:3:50:4 | f2 | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:16:56:16 | i | @@ -23,6 +23,9 @@ | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected index 0cd9366f199..c17bbfd6203 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected @@ -10,6 +10,8 @@ | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:24:56:24 | i | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index 6c910809a61..f491fa10b6e 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -1,41 +1,31 @@ -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | | | ODASA-5186.cpp:4:8:4:8 | declaration | -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | | | ODASA-5186.cpp:4:8:4:8 | declaration | -| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:8 | declaration | -| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:8 | definition | -| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:17 | declaration | -| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:17 | definition | -| ODASA-5186.cpp:8:6:8:9 | test | test | isTopLevel | TopLevelFunction | ODASA-5186.cpp:8:6:8:9 | declaration | -| ODASA-5186.cpp:8:6:8:9 | test | test | isTopLevel | TopLevelFunction | ODASA-5186.cpp:8:6:8:9 | definition | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | | | ODASA-5186.hpp:2:8:2:8 | declaration | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | | | ODASA-5186.hpp:2:8:2:8 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | definition | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | definition | -| functions.cpp:1:6:1:6 | f | f | isTopLevel | TopLevelFunction | functions.cpp:1:6:1:6 | declaration | -| functions.cpp:1:6:1:6 | f | f | isTopLevel | TopLevelFunction | functions.cpp:1:6:1:6 | definition | -| functions.cpp:7:8:7:8 | operator= | operator= | | | functions.cpp:7:8:7:8 | declaration | -| functions.cpp:7:8:7:8 | operator= | operator= | | | functions.cpp:7:8:7:8 | declaration | -| functions.cpp:8:7:8:8 | af | af | | | functions.cpp:8:7:8:8 | declaration | -| functions.cpp:8:7:8:8 | af | af | | | functions.cpp:8:7:8:8 | definition | -| functions.cpp:11:7:11:8 | ag | ag | | | functions.cpp:11:7:11:8 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:5:6:5:6 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:14:6:14:6 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:14:6:14:6 | definition | -| functions.cpp:19:7:19:7 | operator= | operator= | | | functions.cpp:19:7:19:7 | declaration | -| functions.cpp:19:7:19:7 | operator= | operator= | | | functions.cpp:19:7:19:7 | declaration | -| functions.cpp:23:7:23:7 | Table | Table | | | functions.cpp:23:7:23:7 | declaration | -| functions.cpp:23:7:23:7 | operator= | operator= | | | functions.cpp:23:7:23:7 | declaration | -| functions.cpp:27:3:27:7 | Table | Table | | | functions.cpp:27:3:27:7 | declaration | -| functions.cpp:27:3:27:7 | Table | Table | | | functions.cpp:27:3:27:7 | definition | -| functions.cpp:28:3:28:8 | ~Table | ~Table | | | functions.cpp:28:3:28:8 | declaration | -| functions.cpp:28:3:28:8 | ~Table | ~Table | | | functions.cpp:28:3:28:8 | definition | -| functions.cpp:29:9:29:14 | lookup | lookup | | | functions.cpp:29:9:29:14 | declaration | -| functions.cpp:30:8:30:13 | insert | insert | | | functions.cpp:30:8:30:13 | declaration | -| functions.cpp:33:7:33:7 | operator= | operator= | | | functions.cpp:33:7:33:7 | declaration | -| functions.cpp:33:7:33:7 | operator= | operator= | | | functions.cpp:33:7:33:7 | definition | -| functions.cpp:36:2:36:8 | MyClass | MyClass | | | functions.cpp:36:2:36:8 | declaration | -| functions.cpp:37:2:37:8 | MyClass | MyClass | | | functions.cpp:37:2:37:8 | declaration | -| functions.cpp:38:2:38:8 | MyClass | MyClass | | | functions.cpp:38:2:38:8 | declaration | -| functions.cpp:39:2:39:8 | MyClass | MyClass | | | functions.cpp:39:2:39:8 | declaration | -| functions.cpp:40:2:40:13 | operator int | operator int | | | functions.cpp:40:2:40:13 | declaration | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | MyClass && p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | const MyClass & p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | const MyClass & other | declaration:ODASA-5186.cpp:5:8:5:8, definition:ODASA-5186.cpp:5:8:5:8 | +| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | const MyClass & other | declaration:ODASA-5186.cpp:5:8:5:17, definition:ODASA-5186.cpp:5:8:5:17 | +| ODASA-5186.cpp:8:6:8:9 | test | test | | TopLevelFunction, declaration:ODASA-5186.cpp:8:6:8:9, definition:ODASA-5186.cpp:8:6:8:9, isTopLevel | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | NEQ_helper> && p#0 | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | const NEQ_helper> & p#0 | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | const MyClass & x, const MyClass & y | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | const T & x, const T & y | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| functions.cpp:1:6:1:6 | f | f | int a, int b | TopLevelFunction, declaration:functions.cpp:1:6:1:6, definition:functions.cpp:1:6:1:6, isTopLevel | +| functions.cpp:7:8:7:8 | operator= | operator= | A && p#0 | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:7:8:7:8 | operator= | operator= | const A & p#0 | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:8:7:8:8 | af | af | | declaration:functions.cpp:8:7:8:8, definition:functions.cpp:8:7:8:8 | +| functions.cpp:11:7:11:8 | ag | ag | | declaration:functions.cpp:11:7:11:8 | +| functions.cpp:14:6:14:6 | g | g | | TopLevelFunction, declaration:functions.cpp:14:6:14:6, declaration:functions.cpp:5:6:5:6, definition:functions.cpp:14:6:14:6, isTopLevel | +| functions.cpp:19:7:19:7 | operator= | operator= | Name && p#0 | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:19:7:19:7 | operator= | operator= | const Name & p#0 | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:23:7:23:7 | Table | Table | const Table & p#0 | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:23:7:23:7 | operator= | operator= | const Table & p#0 | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:27:3:27:7 | Table | Table | int s | declaration:functions.cpp:27:3:27:7, definition:functions.cpp:27:3:27:7 | +| functions.cpp:28:3:28:8 | ~Table | ~Table | | declaration:functions.cpp:28:3:28:8, definition:functions.cpp:28:3:28:8 | +| functions.cpp:29:9:29:14 | lookup | lookup | const char * p#0 | declaration:functions.cpp:29:9:29:14 | +| functions.cpp:30:8:30:13 | insert | insert | Name * p#0 | declaration:functions.cpp:30:8:30:13 | +| functions.cpp:33:7:33:7 | operator= | operator= | const MyClass & p#0 | declaration:functions.cpp:33:7:33:7, definition:functions.cpp:33:7:33:7 | +| functions.cpp:36:2:36:8 | MyClass | MyClass | | declaration:functions.cpp:36:2:36:8 | +| functions.cpp:37:2:37:8 | MyClass | MyClass | int from | declaration:functions.cpp:37:2:37:8 | +| functions.cpp:38:2:38:8 | MyClass | MyClass | const MyClass & from | declaration:functions.cpp:38:2:38:8 | +| functions.cpp:39:2:39:8 | MyClass | MyClass | MyClass && from | declaration:functions.cpp:39:2:39:8 | +| functions.cpp:40:2:40:13 | operator int | operator int | | declaration:functions.cpp:40:2:40:13 | +| functions.cpp:43:6:43:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | +| functions.cpp:44:6:44:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.ql b/cpp/ql/test/library-tests/functions/functions/Functions1.ql index 22d5b0895c7..4fa7e44ff17 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.ql +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.ql @@ -4,13 +4,18 @@ import cpp -from Function f, string top1, string top2, Location loc, string loctype -where - (if f.isTopLevel() then top1 = "isTopLevel" else top1 = "") and - (if f instanceof TopLevelFunction then top2 = "TopLevelFunction" else top2 = "") and - ( - loc = f.getADeclarationLocation() and loctype = "declaration" - or - loc = f.getDefinitionLocation() and loctype = "definition" - ) -select f, f.getName(), top1, top2, loc.toString(), loctype +string describe(Function f) { + f.isTopLevel() and + result = "isTopLevel" + or + f instanceof TopLevelFunction and + result = "TopLevelFunction" + or + result = "declaration:" + f.getADeclarationLocation() + or + result = "definition:" + f.getDefinitionLocation() +} + +from Function f +where exists(f.getLocation()) +select f, f.getName(), f.getParameterString(), concat(describe(f), ", ") diff --git a/cpp/ql/test/library-tests/functions/functions/functions.cpp b/cpp/ql/test/library-tests/functions/functions/functions.cpp index c47475fdd04..8dd3b9ed151 100644 --- a/cpp/ql/test/library-tests/functions/functions/functions.cpp +++ b/cpp/ql/test/library-tests/functions/functions/functions.cpp @@ -39,3 +39,6 @@ public: MyClass(MyClass &&from); operator int(); }; + +void h(int x); +void h(int y); diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql index 8701725a18d..8e25ba0e5d4 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis import semmle.code.cpp.ir.internal.IntegerConstant diff --git a/cpp/ql/test/library-tests/ir/escape/escape.ql b/cpp/ql/test/library-tests/ir/escape/escape.ql index 9099fea159e..d5c88827af9 100644 --- a/cpp/ql/test/library-tests/ir/escape/escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql index e97cea7670d..e1693ba3f38 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasConfiguration import semmle.code.cpp.ir.implementation.unaliased_ssa.IR diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index a840ec593d7..2e204cde856 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -86,9 +86,9 @@ bad_asts.cpp: # 10| 1: [PointerFieldAccess] x # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 10| -1: [ThisExpr] this +# 10| Type = [PointerType] S * +# 10| ValueCategory = prvalue(load) # 10| 1: [VariableAccess] y # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) @@ -111,9 +111,9 @@ bad_asts.cpp: # 10| 1: [PointerFieldAccess] x # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 10| -1: [ThisExpr] this +# 10| Type = [PointerType] S * +# 10| ValueCategory = prvalue(load) # 10| 1: [VariableAccess] y # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) @@ -219,9 +219,9 @@ bad_asts.cpp: # 33| 0: [VariableAccess] x # 33| Type = [IntType] int # 33| ValueCategory = lvalue -#-----| 1: [ErrorExpr] -#-----| Type = [ErroneousType] error -#-----| ValueCategory = prvalue(load) +# 33| 1: [ErrorExpr] +# 33| Type = [ErroneousType] error +# 33| ValueCategory = prvalue(load) # 34| 3: [ReturnStmt] return ... clang.cpp: # 5| [TopLevelFunction] int* globalIntAddress() @@ -5621,9 +5621,9 @@ ir.cpp: # 645| 0: [PointerFieldAccess] m_a # 645| Type = [IntType] int # 645| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 645| -1: [ThisExpr] this +# 645| Type = [PointerType] C * +# 645| ValueCategory = prvalue(load) # 645| 1: [Literal] 2 # 645| Type = [IntType] int # 645| Value = [Literal] 2 @@ -5673,9 +5673,9 @@ ir.cpp: # 649| 1: [PointerFieldAccess] m_a # 649| Type = [IntType] int # 649| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 649| -1: [ThisExpr] this +# 649| Type = [PointerType] C * +# 649| ValueCategory = prvalue(load) # 650| 7: [ReturnStmt] return ... # 652| [MemberFunction] void C::MethodCalls() # 652| params: @@ -5712,9 +5712,9 @@ ir.cpp: # 655| 0: [FunctionCall] call to InstanceMemberFunction # 655| Type = [IntType] int # 655| ValueCategory = prvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 655| -1: [ThisExpr] this +# 655| Type = [PointerType] C * +# 655| ValueCategory = prvalue(load) # 655| 0: [Literal] 2 # 655| Type = [IntType] int # 655| Value = [Literal] 2 @@ -6173,27 +6173,27 @@ ir.cpp: # 745| expr: [FunctionCall] call to operator= # 745| Type = [LValueReferenceType] String & # 745| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] base_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Base * -#-----| ValueCategory = prvalue(load) +# 745| -1: [AddressOfExpr] & ... +# 745| Type = [PointerType] String * +# 745| ValueCategory = prvalue +# 745| 0: [PointerFieldAccess] base_s +# 745| Type = [Struct] String +# 745| ValueCategory = lvalue +# 745| -1: [ThisExpr] this +# 745| Type = [PointerType] Base * +# 745| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] base_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 745| expr: [ReferenceFieldAccess] base_s +# 745| Type = [Struct] String +# 745| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Base #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Base & -#-----| ValueCategory = prvalue(load) +# 745| expr: [VariableAccess] p#0 +# 745| Type = [LValueReferenceType] const Base & +# 745| ValueCategory = prvalue(load) #-----| 1: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Base & @@ -6258,28 +6258,28 @@ ir.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Base * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Middle * -#-----| ValueCategory = prvalue(load) +# 754| expr: [ThisExpr] this +# 754| Type = [PointerType] Middle * +# 754| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Base & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Base -#-----| ValueCategory = lvalue +# 754| expr: [PointerDereferenceExpr] * ... +# 754| Type = [SpecifiedType] const Base +# 754| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Base *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Base * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Middle * -#-----| ValueCategory = prvalue +# 754| expr: [AddressOfExpr] & ... +# 754| Type = [PointerType] const Middle * +# 754| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Middle #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Middle & -#-----| ValueCategory = prvalue(load) +# 754| expr: [VariableAccess] p#0 +# 754| Type = [LValueReferenceType] const Middle & +# 754| ValueCategory = prvalue(load) #-----| 1: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] String @@ -6287,27 +6287,27 @@ ir.cpp: # 754| expr: [FunctionCall] call to operator= # 754| Type = [LValueReferenceType] String & # 754| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] middle_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Middle * -#-----| ValueCategory = prvalue(load) +# 754| -1: [AddressOfExpr] & ... +# 754| Type = [PointerType] String * +# 754| ValueCategory = prvalue +# 754| 0: [PointerFieldAccess] middle_s +# 754| Type = [Struct] String +# 754| ValueCategory = lvalue +# 754| -1: [ThisExpr] this +# 754| Type = [PointerType] Middle * +# 754| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] middle_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 754| expr: [ReferenceFieldAccess] middle_s +# 754| Type = [Struct] String +# 754| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Middle #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Middle & -#-----| ValueCategory = prvalue(load) +# 754| expr: [VariableAccess] p#0 +# 754| Type = [LValueReferenceType] const Middle & +# 754| ValueCategory = prvalue(load) #-----| 2: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Middle & @@ -6369,28 +6369,28 @@ ir.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Middle * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 763| expr: [ThisExpr] this +# 763| Type = [PointerType] Derived * +# 763| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Middle & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Middle -#-----| ValueCategory = lvalue +# 763| expr: [PointerDereferenceExpr] * ... +# 763| Type = [SpecifiedType] const Middle +# 763| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Middle *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Middle * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Derived * -#-----| ValueCategory = prvalue +# 763| expr: [AddressOfExpr] & ... +# 763| Type = [PointerType] const Derived * +# 763| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 763| expr: [VariableAccess] p#0 +# 763| Type = [LValueReferenceType] const Derived & +# 763| ValueCategory = prvalue(load) #-----| 1: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] String @@ -6398,27 +6398,27 @@ ir.cpp: # 763| expr: [FunctionCall] call to operator= # 763| Type = [LValueReferenceType] String & # 763| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] derived_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 763| -1: [AddressOfExpr] & ... +# 763| Type = [PointerType] String * +# 763| ValueCategory = prvalue +# 763| 0: [PointerFieldAccess] derived_s +# 763| Type = [Struct] String +# 763| ValueCategory = lvalue +# 763| -1: [ThisExpr] this +# 763| Type = [PointerType] Derived * +# 763| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] derived_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 763| expr: [ReferenceFieldAccess] derived_s +# 763| Type = [Struct] String +# 763| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 763| expr: [VariableAccess] p#0 +# 763| Type = [LValueReferenceType] const Derived & +# 763| ValueCategory = prvalue(load) #-----| 2: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Derived & @@ -8533,15 +8533,15 @@ ir.cpp: # 1043| expr: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [SpecifiedType] const String # 1043| ValueCategory = lvalue -#-----| expr: [VariableAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) +# 1043| expr: [VariableAccess] s +# 1043| Type = [LValueReferenceType] const String & +# 1043| ValueCategory = prvalue(load) #-----| .x: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] int & #-----| ValueCategory = prvalue -#-----| expr: [VariableAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = lvalue +# 1043| expr: [VariableAccess] x +# 1043| Type = [IntType] int +# 1043| ValueCategory = lvalue # 1044| 3: [ExprStmt] ExprStmt # 1044| 0: [FunctionCall] call to operator() # 1044| Type = [PlainCharType] char @@ -8572,12 +8572,12 @@ ir.cpp: # 1045| 0: [ClassAggregateLiteral] {...} # 1045| Type = [Closure,LocalClass] decltype([...](...){...}) # 1045| ValueCategory = prvalue -#-----| .s: [ConstructorCall] call to String -#-----| Type = [VoidType] void -#-----| ValueCategory = prvalue -#-----| .x: [VariableAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) +# 1045| .s: [ConstructorCall] call to String +# 1045| Type = [VoidType] void +# 1045| ValueCategory = prvalue +# 1045| .x: [VariableAccess] x +# 1045| Type = [IntType] int +# 1045| ValueCategory = prvalue(load) # 1046| 5: [ExprStmt] ExprStmt # 1046| 0: [FunctionCall] call to operator() # 1046| Type = [PlainCharType] char @@ -8647,9 +8647,9 @@ ir.cpp: # 1049| 0: [ClassAggregateLiteral] {...} # 1049| Type = [Closure,LocalClass] decltype([...](...){...}) # 1049| ValueCategory = prvalue -#-----| .s: [ConstructorCall] call to String -#-----| Type = [VoidType] void -#-----| ValueCategory = prvalue +# 1049| .s: [ConstructorCall] call to String +# 1049| Type = [VoidType] void +# 1049| ValueCategory = prvalue # 1050| 9: [ExprStmt] ExprStmt # 1050| 0: [FunctionCall] call to operator() # 1050| Type = [PlainCharType] char @@ -8849,21 +8849,21 @@ ir.cpp: # 1043| -1: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [SpecifiedType] const String # 1043| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1043, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1043| expr: [PointerFieldAccess] s +# 1043| Type = [LValueReferenceType] const String & +# 1043| ValueCategory = prvalue(load) +# 1043| -1: [ThisExpr] this +# 1043| Type = [PointerType] const lambda [] type at line 1043, col. 21 * +# 1043| ValueCategory = prvalue(load) # 1043| 1: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [IntType] int # 1043| ValueCategory = prvalue(load) -#-----| expr: [PointerFieldAccess] x -#-----| Type = [LValueReferenceType] int & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1043, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1043| expr: [PointerFieldAccess] x +# 1043| Type = [LValueReferenceType] int & +# 1043| ValueCategory = prvalue(load) +# 1043| -1: [ThisExpr] this +# 1043| Type = [PointerType] const lambda [] type at line 1043, col. 21 * +# 1043| ValueCategory = prvalue(load) # 1045| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)& (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21) const&) # 1045| params: #-----| 0: [Parameter] p#0 @@ -8904,18 +8904,18 @@ ir.cpp: # 1045| 0: [FunctionCall] call to c_str # 1045| Type = [PointerType] const char * # 1045| ValueCategory = prvalue -#-----| -1: [PointerFieldAccess] s -#-----| Type = [SpecifiedType] const String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1045, col. 21 * -#-----| ValueCategory = prvalue(load) -#-----| 1: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1045, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1045| -1: [PointerFieldAccess] s +# 1045| Type = [SpecifiedType] const String +# 1045| ValueCategory = lvalue +# 1045| -1: [ThisExpr] this +# 1045| Type = [PointerType] const lambda [] type at line 1045, col. 21 * +# 1045| ValueCategory = prvalue(load) +# 1045| 1: [PointerFieldAccess] x +# 1045| Type = [IntType] int +# 1045| ValueCategory = prvalue(load) +# 1045| -1: [ThisExpr] this +# 1045| Type = [PointerType] const lambda [] type at line 1045, col. 21 * +# 1045| ValueCategory = prvalue(load) # 1047| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)& (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30) const&) # 1047| params: #-----| 0: [Parameter] p#0 @@ -8945,12 +8945,12 @@ ir.cpp: # 1047| -1: [ReferenceDereferenceExpr] (reference dereference) # 1047| Type = [SpecifiedType] const String # 1047| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1047, col. 30 * -#-----| ValueCategory = prvalue(load) +# 1047| expr: [PointerFieldAccess] s +# 1047| Type = [LValueReferenceType] const String & +# 1047| ValueCategory = prvalue(load) +# 1047| -1: [ThisExpr] this +# 1047| Type = [PointerType] const lambda [] type at line 1047, col. 30 * +# 1047| ValueCategory = prvalue(load) # 1047| 1: [Literal] 0 # 1047| Type = [IntType] int # 1047| Value = [Literal] 0 @@ -8995,12 +8995,12 @@ ir.cpp: # 1049| 0: [FunctionCall] call to c_str # 1049| Type = [PointerType] const char * # 1049| ValueCategory = prvalue -#-----| -1: [PointerFieldAccess] s -#-----| Type = [SpecifiedType] const String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1049, col. 30 * -#-----| ValueCategory = prvalue(load) +# 1049| -1: [PointerFieldAccess] s +# 1049| Type = [SpecifiedType] const String +# 1049| ValueCategory = lvalue +# 1049| -1: [ThisExpr] this +# 1049| Type = [PointerType] const lambda [] type at line 1049, col. 30 * +# 1049| ValueCategory = prvalue(load) # 1049| 1: [Literal] 0 # 1049| Type = [IntType] int # 1049| Value = [Literal] 0 @@ -9034,18 +9034,18 @@ ir.cpp: # 1051| -1: [ReferenceDereferenceExpr] (reference dereference) # 1051| Type = [SpecifiedType] const String # 1051| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1051, col. 32 * -#-----| ValueCategory = prvalue(load) -#-----| 1: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1051, col. 32 * -#-----| ValueCategory = prvalue(load) +# 1051| expr: [PointerFieldAccess] s +# 1051| Type = [LValueReferenceType] const String & +# 1051| ValueCategory = prvalue(load) +# 1051| -1: [ThisExpr] this +# 1051| Type = [PointerType] const lambda [] type at line 1051, col. 32 * +# 1051| ValueCategory = prvalue(load) +# 1051| 1: [PointerFieldAccess] x +# 1051| Type = [IntType] int +# 1051| ValueCategory = prvalue(load) +# 1051| -1: [ThisExpr] this +# 1051| Type = [PointerType] const lambda [] type at line 1051, col. 32 * +# 1051| ValueCategory = prvalue(load) # 1054| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)& (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23) const&) # 1054| params: #-----| 0: [Parameter] p#0 @@ -9075,39 +9075,39 @@ ir.cpp: # 1054| -1: [ReferenceDereferenceExpr] (reference dereference) # 1054| Type = [SpecifiedType] const String # 1054| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| expr: [PointerFieldAccess] s +# 1054| Type = [LValueReferenceType] const String & +# 1054| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [SubExpr] ... - ... # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue # 1054| 0: [AddExpr] ... + ... # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| 0: [PointerFieldAccess] x +# 1054| Type = [IntType] int +# 1054| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [PointerFieldAccess] i # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [ReferenceDereferenceExpr] (reference dereference) # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue(load) # 1054| expr: [PointerFieldAccess] j # 1054| Type = [LValueReferenceType] int & # 1054| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1059| [CopyAssignmentOperator] vector& vector::operator=(vector const&) # 1059| params: #-----| 0: [Parameter] p#0 @@ -9175,21 +9175,21 @@ ir.cpp: #-----| Conversion = [GlvalueConversion] glvalue conversion #-----| Type = [SpecifiedType] const iterator #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue -#-----| 0: [VariableAccess] (__end) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = prvalue(load) +# 1078| expr: [VariableAccess] (__begin) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = lvalue +# 1078| 0: [VariableAccess] (__end) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = prvalue(load) # 1078| 3: [ReferenceDereferenceExpr] (reference dereference) # 1078| Type = [NestedStruct] iterator # 1078| ValueCategory = lvalue # 1078| expr: [FunctionCall] call to operator++ # 1078| Type = [LValueReferenceType] iterator & # 1078| ValueCategory = prvalue -#-----| -1: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue +# 1078| -1: [VariableAccess] (__begin) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = lvalue # 1078| 4: [DeclStmt] declaration # 1078| 5: [Block] { ... } # 1079| 0: [IfStmt] if (...) ... @@ -9216,21 +9216,21 @@ ir.cpp: #-----| Conversion = [GlvalueConversion] glvalue conversion #-----| Type = [SpecifiedType] const iterator #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue -#-----| 0: [VariableAccess] (__end) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = prvalue(load) +# 1084| expr: [VariableAccess] (__begin) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = lvalue +# 1084| 0: [VariableAccess] (__end) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = prvalue(load) # 1084| 3: [ReferenceDereferenceExpr] (reference dereference) # 1084| Type = [NestedStruct] iterator # 1084| ValueCategory = lvalue # 1084| expr: [FunctionCall] call to operator++ # 1084| Type = [LValueReferenceType] iterator & # 1084| ValueCategory = prvalue -#-----| -1: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue +# 1084| -1: [VariableAccess] (__begin) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = lvalue # 1084| 4: [DeclStmt] declaration # 1084| 5: [Block] { ... } # 1085| 0: [IfStmt] if (...) ... @@ -9535,10 +9535,10 @@ ir.cpp: # 1166| 1: [VariableAccess] vi4 # 1166| Type = [SpecifiedType] __attribute((vector_size(16UL))) int # 1166| ValueCategory = prvalue(load) -#-----| 2: [AddExpr] ... + ... -#-----| Type = [IntType] int -#-----| Value = [AddExpr] 3 -#-----| ValueCategory = prvalue +# 1166| 2: [AddExpr] ... + ... +# 1166| Type = [IntType] int +# 1166| Value = [AddExpr] 3 +# 1166| ValueCategory = prvalue # 1166| 0: [Literal] 3 # 1166| Type = [IntType] int # 1166| Value = [Literal] 3 @@ -10483,6 +10483,35 @@ ir.cpp: # 1315| 2: [VariableAccess] y # 1315| Type = [IntType] int # 1315| ValueCategory = prvalue(load) +# 1318| [Operator,TopLevelFunction] void* operator new(size_t, void*) +# 1318| params: +# 1318| 0: [Parameter] p#0 +# 1318| Type = [CTypedefType,Size_t] size_t +# 1318| 1: [Parameter] p#1 +# 1318| Type = [VoidPointerType] void * +# 1320| [TopLevelFunction] void f(int*) +# 1320| params: +# 1320| 0: [Parameter] p +# 1320| Type = [IntPointerType] int * +# 1321| body: [Block] { ... } +# 1322| 0: [ExprStmt] ExprStmt +# 1322| 0: [NewExpr] new +# 1322| Type = [IntPointerType] int * +# 1322| ValueCategory = prvalue +# 1322| 0: [FunctionCall] call to operator new +# 1322| Type = [VoidPointerType] void * +# 1322| ValueCategory = prvalue +# 1322| 0: [ErrorExpr] +# 1322| Type = [LongType] unsigned long +# 1322| ValueCategory = prvalue +# 1322| 1: [CStyleCast] (void *)... +# 1322| Conversion = [PointerConversion] pointer conversion +# 1322| Type = [VoidPointerType] void * +# 1322| ValueCategory = prvalue +# 1322| expr: [VariableAccess] p +# 1322| Type = [IntPointerType] int * +# 1322| ValueCategory = prvalue(load) +# 1323| 1: [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| params: diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected similarity index 82% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql new file mode 100644 index 00000000000..847991163c8 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected similarity index 82% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql deleted file mode 100644 index 74fa11944a6..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected similarity index 62% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql similarity index 90% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql index b3962e34648..b9d03404338 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected similarity index 62% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..d0a29f0641a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 8e348011785..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 5be14bf986c..54b198d9537 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1315,4 +1315,11 @@ int shortCircuitConditional(int x, int y) { return predicateA() && predicateB() ? x : y; } +void *operator new(size_t, void *) noexcept; + +void f(int* p) +{ + new (p) int; +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected similarity index 82% rename from cpp/ql/test/library-tests/ir/ir/raw_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref b/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref new file mode 100644 index 00000000000..eb7cc77b316 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index e83fea6badc..a2be838ae48 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -1,35 +1,37 @@ bad_asts.cpp: # 9| int Bad::S::MemberFunction(int) # 9| Block 0 -# 9| v9_1(void) = EnterFunction : -# 9| mu9_2(unknown) = AliasedDefinition : -# 9| mu9_3(unknown) = InitializeNonLocal : -# 9| mu9_4(unknown) = UnmodeledDefinition : -# 9| r9_5(glval) = InitializeThis : -# 9| r9_6(glval) = VariableAddress[y] : -# 9| mu9_7(int) = InitializeParameter[y] : &:r9_6 -# 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(int) = Constant[6] : -#-----| r0_1(S *) = CopyValue : r9_5 -# 10| r10_3(glval) = FieldAddress[x] : r0_1 -# 10| r10_4(int) = Load : &:r10_3, ~mu9_4 -# 10| r10_5(int) = Add : r10_2, r10_4 -# 10| r10_6(glval) = VariableAddress[y] : -# 10| r10_7(int) = Load : &:r10_6, ~mu9_4 -# 10| r10_8(int) = Add : r10_5, r10_7 -# 10| mu10_9(int) = Store : &:r10_1, r10_8 -# 9| r9_8(glval) = VariableAddress[#return] : -# 9| v9_9(void) = ReturnValue : &:r9_8, ~mu9_4 -# 9| v9_10(void) = UnmodeledUse : mu* -# 9| v9_11(void) = AliasedUse : ~mu9_4 -# 9| v9_12(void) = ExitFunction : +# 9| v9_1(void) = EnterFunction : +# 9| mu9_2(unknown) = AliasedDefinition : +# 9| mu9_3(unknown) = InitializeNonLocal : +# 9| r9_4(glval) = VariableAddress[#this] : +# 9| mu9_5(glval) = InitializeParameter[#this] : &:r9_4 +# 9| r9_6(glval) = Load : &:r9_4, ~m? +# 9| mu9_7(S) = InitializeIndirection[#this] : &:r9_6 +# 9| r9_8(glval) = VariableAddress[y] : +# 9| mu9_9(int) = InitializeParameter[y] : &:r9_8 +# 10| r10_1(glval) = VariableAddress[#return] : +# 10| r10_2(int) = Constant[6] : +# 10| r10_3(glval) = VariableAddress[#this] : +# 10| r10_4(S *) = Load : &:r10_3, ~m? +# 10| r10_5(glval) = FieldAddress[x] : r10_4 +# 10| r10_6(int) = Load : &:r10_5, ~m? +# 10| r10_7(int) = Add : r10_2, r10_6 +# 10| r10_8(glval) = VariableAddress[y] : +# 10| r10_9(int) = Load : &:r10_8, ~m? +# 10| r10_10(int) = Add : r10_7, r10_9 +# 10| mu10_11(int) = Store : &:r10_1, r10_10 +# 9| v9_10(void) = ReturnIndirection[#this] : &:r9_6, ~m? +# 9| r9_11(glval) = VariableAddress[#return] : +# 9| v9_12(void) = ReturnValue : &:r9_11, ~m? +# 9| v9_13(void) = AliasedUse : ~m? +# 9| v9_14(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 # 14| v14_1(void) = EnterFunction : # 14| mu14_2(unknown) = AliasedDefinition : # 14| mu14_3(unknown) = InitializeNonLocal : -# 14| mu14_4(unknown) = UnmodeledDefinition : # 15| r15_1(glval) = VariableAddress[s] : # 15| mu15_2(S) = Uninitialized[s] : &:r15_1 # 15| r15_3(glval) = FieldAddress[x] : r15_1 @@ -39,73 +41,70 @@ bad_asts.cpp: # 16| r16_2(glval) = FunctionAddress[MemberFunction] : # 16| r16_3(int) = Constant[1] : # 16| r16_4(int) = Call : func:r16_2, this:r16_1, 0:r16_3 -# 16| mu16_5(unknown) = ^CallSideEffect : ~mu14_4 -# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~mu14_4 +# 16| mu16_5(unknown) = ^CallSideEffect : ~m? +# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~m? # 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1 # 17| v17_1(void) = NoOp : -# 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = UnmodeledUse : mu* -# 14| v14_7(void) = AliasedUse : ~mu14_4 -# 14| v14_8(void) = ExitFunction : +# 14| v14_4(void) = ReturnVoid : +# 14| v14_5(void) = AliasedUse : ~m? +# 14| v14_6(void) = ExitFunction : # 22| void Bad::Point::Point() # 22| Block 0 -# 22| v22_1(void) = EnterFunction : -# 22| mu22_2(unknown) = AliasedDefinition : -# 22| mu22_3(unknown) = InitializeNonLocal : -# 22| mu22_4(unknown) = UnmodeledDefinition : -# 22| r22_5(glval) = InitializeThis : -# 23| v23_1(void) = NoOp : -# 22| v22_6(void) = ReturnVoid : -# 22| v22_7(void) = UnmodeledUse : mu* -# 22| v22_8(void) = AliasedUse : ~mu22_4 -# 22| v22_9(void) = ExitFunction : +# 22| v22_1(void) = EnterFunction : +# 22| mu22_2(unknown) = AliasedDefinition : +# 22| mu22_3(unknown) = InitializeNonLocal : +# 22| r22_4(glval) = VariableAddress[#this] : +# 22| mu22_5(glval) = InitializeParameter[#this] : &:r22_4 +# 22| r22_6(glval) = Load : &:r22_4, ~m? +# 22| mu22_7(Point) = InitializeIndirection[#this] : &:r22_6 +# 23| v23_1(void) = NoOp : +# 22| v22_8(void) = ReturnIndirection[#this] : &:r22_6, ~m? +# 22| v22_9(void) = ReturnVoid : +# 22| v22_10(void) = AliasedUse : ~m? +# 22| v22_11(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 # 26| v26_1(void) = EnterFunction : # 26| mu26_2(unknown) = AliasedDefinition : # 26| mu26_3(unknown) = InitializeNonLocal : -# 26| mu26_4(unknown) = UnmodeledDefinition : -# 26| r26_5(glval) = VariableAddress[a] : -# 26| mu26_6(Point &) = InitializeParameter[a] : &:r26_5 -# 26| r26_7(Point &) = Load : &:r26_5, ~mu26_4 -# 26| mu26_8(unknown) = InitializeIndirection[a] : &:r26_7 +# 26| r26_4(glval) = VariableAddress[a] : +# 26| mu26_5(Point &) = InitializeParameter[a] : &:r26_4 +# 26| r26_6(Point &) = Load : &:r26_4, ~m? +# 26| mu26_7(unknown) = InitializeIndirection[a] : &:r26_6 # 27| r27_1(glval) = VariableAddress[b] : # 27| r27_2(glval) = VariableAddress[a] : -# 27| r27_3(Point &) = Load : &:r27_2, ~mu26_4 +# 27| r27_3(Point &) = Load : &:r27_2, ~m? # 27| r27_4(glval) = CopyValue : r27_3 # 27| r27_5(glval) = Convert : r27_4 -# 27| r27_6(Point) = Load : &:r27_5, ~mu26_4 +# 27| r27_6(Point) = Load : &:r27_5, ~m? # 27| mu27_7(Point) = Store : &:r27_1, r27_6 # 28| v28_1(void) = NoOp : -# 26| v26_9(void) = ReturnIndirection[a] : &:r26_7, ~mu26_4 -# 26| v26_10(void) = ReturnVoid : -# 26| v26_11(void) = UnmodeledUse : mu* -# 26| v26_12(void) = AliasedUse : ~mu26_4 -# 26| v26_13(void) = ExitFunction : +# 26| v26_8(void) = ReturnIndirection[a] : &:r26_6, ~m? +# 26| v26_9(void) = ReturnVoid : +# 26| v26_10(void) = AliasedUse : ~m? +# 26| v26_11(void) = ExitFunction : # 30| void Bad::errorExpr() # 30| Block 0 # 30| v30_1(void) = EnterFunction : # 30| mu30_2(unknown) = AliasedDefinition : # 30| mu30_3(unknown) = InitializeNonLocal : -# 30| mu30_4(unknown) = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[intref] : # 31| r31_2(error) = Error : # 31| mu31_3(int &) = Store : &:r31_1, r31_2 # 32| r32_1(glval) = VariableAddress[x] : # 32| r32_2(error) = Error : # 32| mu32_3(int) = Store : &:r32_1, r32_2 -#-----| r0_1(glval) = Error : -#-----| r0_2(error) = Load : &:r0_1, ~mu30_4 -# 33| r33_1(glval) = VariableAddress[x] : -# 33| mu33_2(int) = Store : &:r33_1, r0_2 +# 33| r33_1(glval) = Error : +# 33| r33_2(error) = Load : &:r33_1, ~m? +# 33| r33_3(glval) = VariableAddress[x] : +# 33| mu33_4(int) = Store : &:r33_3, r33_2 # 34| v34_1(void) = NoOp : -# 30| v30_5(void) = ReturnVoid : -# 30| v30_6(void) = UnmodeledUse : mu* -# 30| v30_7(void) = AliasedUse : ~mu30_4 -# 30| v30_8(void) = ExitFunction : +# 30| v30_4(void) = ReturnVoid : +# 30| v30_5(void) = AliasedUse : ~m? +# 30| v30_6(void) = ExitFunction : clang.cpp: # 5| int* globalIntAddress() @@ -113,16 +112,14 @@ clang.cpp: # 5| v5_1(void) = EnterFunction : # 5| mu5_2(unknown) = AliasedDefinition : # 5| mu5_3(unknown) = InitializeNonLocal : -# 5| mu5_4(unknown) = UnmodeledDefinition : # 6| r6_1(glval) = VariableAddress[#return] : # 6| r6_2(glval) = VariableAddress[globalInt] : # 6| r6_3(int *) = CopyValue : r6_2 # 6| mu6_4(int *) = Store : &:r6_1, r6_3 -# 5| r5_5(glval) = VariableAddress[#return] : -# 5| v5_6(void) = ReturnValue : &:r5_5, ~mu5_4 -# 5| v5_7(void) = UnmodeledUse : mu* -# 5| v5_8(void) = AliasedUse : ~mu5_4 -# 5| v5_9(void) = ExitFunction : +# 5| r5_4(glval) = VariableAddress[#return] : +# 5| v5_5(void) = ReturnValue : &:r5_4, ~m? +# 5| v5_6(void) = AliasedUse : ~m? +# 5| v5_7(void) = ExitFunction : complex.c: # 1| void complex_literals() @@ -130,7 +127,6 @@ complex.c: # 1| v1_1(void) = EnterFunction : # 1| mu1_2(unknown) = AliasedDefinition : # 1| mu1_3(unknown) = InitializeNonLocal : -# 1| mu1_4(unknown) = UnmodeledDefinition : # 2| r2_1(glval<_Complex float>) = VariableAddress[cf] : # 2| r2_2(double) = Constant[2.0] : # 2| r2_3(_Complex float) = Convert : r2_2 @@ -167,17 +163,15 @@ complex.c: # 11| r11_3(_Imaginary long double) = Convert : r11_2 # 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3 # 12| v12_1(void) = NoOp : -# 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = UnmodeledUse : mu* -# 1| v1_7(void) = AliasedUse : ~mu1_4 -# 1| v1_8(void) = ExitFunction : +# 1| v1_4(void) = ReturnVoid : +# 1| v1_5(void) = AliasedUse : ~m? +# 1| v1_6(void) = ExitFunction : # 14| void complex_arithmetic() # 14| Block 0 # 14| v14_1(void) = EnterFunction : # 14| mu14_2(unknown) = AliasedDefinition : # 14| mu14_3(unknown) = InitializeNonLocal : -# 14| mu14_4(unknown) = UnmodeledDefinition : # 15| r15_1(glval) = VariableAddress[f1] : # 15| r15_2(float) = Constant[5.0] : # 15| mu15_3(float) = Store : &:r15_1, r15_2 @@ -205,149 +199,147 @@ complex.c: # 23| r23_1(glval<_Imaginary float>) = VariableAddress[jf3] : # 23| mu23_2(_Imaginary float) = Uninitialized[jf3] : &:r23_1 # 26| r26_1(glval<_Complex float>) = VariableAddress[cf1] : -# 26| r26_2(_Complex float) = Load : &:r26_1, ~mu14_4 +# 26| r26_2(_Complex float) = Load : &:r26_1, ~m? # 26| r26_3(_Complex float) = CopyValue : r26_2 # 26| r26_4(glval<_Complex float>) = VariableAddress[cf3] : # 26| mu26_5(_Complex float) = Store : &:r26_4, r26_3 # 27| r27_1(glval<_Complex float>) = VariableAddress[cf1] : -# 27| r27_2(_Complex float) = Load : &:r27_1, ~mu14_4 +# 27| r27_2(_Complex float) = Load : &:r27_1, ~m? # 27| r27_3(_Complex float) = Negate : r27_2 # 27| r27_4(glval<_Complex float>) = VariableAddress[cf3] : # 27| mu27_5(_Complex float) = Store : &:r27_4, r27_3 # 30| r30_1(glval<_Complex float>) = VariableAddress[cf1] : -# 30| r30_2(_Complex float) = Load : &:r30_1, ~mu14_4 +# 30| r30_2(_Complex float) = Load : &:r30_1, ~m? # 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] : -# 30| r30_4(_Complex float) = Load : &:r30_3, ~mu14_4 +# 30| r30_4(_Complex float) = Load : &:r30_3, ~m? # 30| r30_5(_Complex float) = Add : r30_2, r30_4 # 30| r30_6(glval<_Complex float>) = VariableAddress[cf3] : # 30| mu30_7(_Complex float) = Store : &:r30_6, r30_5 # 31| r31_1(glval<_Complex float>) = VariableAddress[cf1] : -# 31| r31_2(_Complex float) = Load : &:r31_1, ~mu14_4 +# 31| r31_2(_Complex float) = Load : &:r31_1, ~m? # 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] : -# 31| r31_4(_Complex float) = Load : &:r31_3, ~mu14_4 +# 31| r31_4(_Complex float) = Load : &:r31_3, ~m? # 31| r31_5(_Complex float) = Sub : r31_2, r31_4 # 31| r31_6(glval<_Complex float>) = VariableAddress[cf3] : # 31| mu31_7(_Complex float) = Store : &:r31_6, r31_5 # 32| r32_1(glval<_Complex float>) = VariableAddress[cf1] : -# 32| r32_2(_Complex float) = Load : &:r32_1, ~mu14_4 +# 32| r32_2(_Complex float) = Load : &:r32_1, ~m? # 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] : -# 32| r32_4(_Complex float) = Load : &:r32_3, ~mu14_4 +# 32| r32_4(_Complex float) = Load : &:r32_3, ~m? # 32| r32_5(_Complex float) = Mul : r32_2, r32_4 # 32| r32_6(glval<_Complex float>) = VariableAddress[cf3] : # 32| mu32_7(_Complex float) = Store : &:r32_6, r32_5 # 33| r33_1(glval<_Complex float>) = VariableAddress[cf1] : -# 33| r33_2(_Complex float) = Load : &:r33_1, ~mu14_4 +# 33| r33_2(_Complex float) = Load : &:r33_1, ~m? # 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] : -# 33| r33_4(_Complex float) = Load : &:r33_3, ~mu14_4 +# 33| r33_4(_Complex float) = Load : &:r33_3, ~m? # 33| r33_5(_Complex float) = Div : r33_2, r33_4 # 33| r33_6(glval<_Complex float>) = VariableAddress[cf3] : # 33| mu33_7(_Complex float) = Store : &:r33_6, r33_5 # 36| r36_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~mu14_4 +# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~m? # 36| r36_3(_Imaginary float) = CopyValue : r36_2 # 36| r36_4(glval<_Imaginary float>) = VariableAddress[jf3] : # 36| mu36_5(_Imaginary float) = Store : &:r36_4, r36_3 # 37| r37_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~mu14_4 +# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~m? # 37| r37_3(_Imaginary float) = Negate : r37_2 # 37| r37_4(glval<_Imaginary float>) = VariableAddress[jf3] : # 37| mu37_5(_Imaginary float) = Store : &:r37_4, r37_3 # 40| r40_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~mu14_4 +# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~m? # 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~mu14_4 +# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~m? # 40| r40_5(_Imaginary float) = Add : r40_2, r40_4 # 40| r40_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 40| mu40_7(_Imaginary float) = Store : &:r40_6, r40_5 # 41| r41_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~mu14_4 +# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~m? # 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~mu14_4 +# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~m? # 41| r41_5(_Imaginary float) = Sub : r41_2, r41_4 # 41| r41_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 41| mu41_7(_Imaginary float) = Store : &:r41_6, r41_5 # 42| r42_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~mu14_4 +# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~m? # 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~mu14_4 +# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~m? # 42| r42_5(float) = Mul : r42_2, r42_4 # 42| r42_6(glval) = VariableAddress[f3] : # 42| mu42_7(float) = Store : &:r42_6, r42_5 # 43| r43_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~mu14_4 +# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~m? # 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~mu14_4 +# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~m? # 43| r43_5(float) = Div : r43_2, r43_4 # 43| r43_6(glval) = VariableAddress[f3] : # 43| mu43_7(float) = Store : &:r43_6, r43_5 # 46| r46_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~mu14_4 +# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~m? # 46| r46_3(glval) = VariableAddress[f2] : -# 46| r46_4(float) = Load : &:r46_3, ~mu14_4 +# 46| r46_4(float) = Load : &:r46_3, ~m? # 46| r46_5(_Complex float) = Add : r46_2, r46_4 # 46| r46_6(glval<_Complex float>) = VariableAddress[cf3] : # 46| mu46_7(_Complex float) = Store : &:r46_6, r46_5 # 47| r47_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~mu14_4 +# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~m? # 47| r47_3(glval) = VariableAddress[f2] : -# 47| r47_4(float) = Load : &:r47_3, ~mu14_4 +# 47| r47_4(float) = Load : &:r47_3, ~m? # 47| r47_5(_Complex float) = Sub : r47_2, r47_4 # 47| r47_6(glval<_Complex float>) = VariableAddress[cf3] : # 47| mu47_7(_Complex float) = Store : &:r47_6, r47_5 # 48| r48_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~mu14_4 +# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~m? # 48| r48_3(glval) = VariableAddress[f2] : -# 48| r48_4(float) = Load : &:r48_3, ~mu14_4 +# 48| r48_4(float) = Load : &:r48_3, ~m? # 48| r48_5(_Imaginary float) = Mul : r48_2, r48_4 # 48| r48_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 48| mu48_7(_Imaginary float) = Store : &:r48_6, r48_5 # 49| r49_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~mu14_4 +# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~m? # 49| r49_3(glval) = VariableAddress[f2] : -# 49| r49_4(float) = Load : &:r49_3, ~mu14_4 +# 49| r49_4(float) = Load : &:r49_3, ~m? # 49| r49_5(_Imaginary float) = Div : r49_2, r49_4 # 49| r49_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 49| mu49_7(_Imaginary float) = Store : &:r49_6, r49_5 # 52| r52_1(glval) = VariableAddress[f1] : -# 52| r52_2(float) = Load : &:r52_1, ~mu14_4 +# 52| r52_2(float) = Load : &:r52_1, ~m? # 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~mu14_4 +# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~m? # 52| r52_5(_Complex float) = Add : r52_2, r52_4 # 52| r52_6(glval<_Complex float>) = VariableAddress[cf3] : # 52| mu52_7(_Complex float) = Store : &:r52_6, r52_5 # 53| r53_1(glval) = VariableAddress[f1] : -# 53| r53_2(float) = Load : &:r53_1, ~mu14_4 +# 53| r53_2(float) = Load : &:r53_1, ~m? # 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~mu14_4 +# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~m? # 53| r53_5(_Complex float) = Sub : r53_2, r53_4 # 53| r53_6(glval<_Complex float>) = VariableAddress[cf3] : # 53| mu53_7(_Complex float) = Store : &:r53_6, r53_5 # 54| r54_1(glval) = VariableAddress[f1] : -# 54| r54_2(float) = Load : &:r54_1, ~mu14_4 +# 54| r54_2(float) = Load : &:r54_1, ~m? # 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~mu14_4 +# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~m? # 54| r54_5(_Imaginary float) = Mul : r54_2, r54_4 # 54| r54_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 54| mu54_7(_Imaginary float) = Store : &:r54_6, r54_5 # 55| r55_1(glval) = VariableAddress[f1] : -# 55| r55_2(float) = Load : &:r55_1, ~mu14_4 +# 55| r55_2(float) = Load : &:r55_1, ~m? # 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~mu14_4 +# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~m? # 55| r55_5(_Imaginary float) = Div : r55_2, r55_4 # 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 # 56| v56_1(void) = NoOp : -# 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = UnmodeledUse : mu* -# 14| v14_7(void) = AliasedUse : ~mu14_4 -# 14| v14_8(void) = ExitFunction : +# 14| v14_4(void) = ReturnVoid : +# 14| v14_5(void) = AliasedUse : ~m? +# 14| v14_6(void) = ExitFunction : # 58| void complex_conversions() # 58| Block 0 # 58| v58_1(void) = EnterFunction : # 58| mu58_2(unknown) = AliasedDefinition : # 58| mu58_3(unknown) = InitializeNonLocal : -# 58| mu58_4(unknown) = UnmodeledDefinition : # 59| r59_1(glval) = VariableAddress[f] : # 59| r59_2(float) = Constant[2.0] : # 59| mu59_3(float) = Store : &:r59_1, r59_2 @@ -381,322 +373,321 @@ complex.c: # 67| r67_3(_Imaginary long double) = Convert : r67_2 # 67| mu67_4(_Imaginary long double) = Store : &:r67_1, r67_3 # 70| r70_1(glval<_Complex float>) = VariableAddress[cf] : -# 70| r70_2(_Complex float) = Load : &:r70_1, ~mu58_4 +# 70| r70_2(_Complex float) = Load : &:r70_1, ~m? # 70| r70_3(glval<_Complex float>) = VariableAddress[cf] : # 70| mu70_4(_Complex float) = Store : &:r70_3, r70_2 # 71| r71_1(glval<_Complex double>) = VariableAddress[cd] : -# 71| r71_2(_Complex double) = Load : &:r71_1, ~mu58_4 +# 71| r71_2(_Complex double) = Load : &:r71_1, ~m? # 71| r71_3(_Complex float) = Convert : r71_2 # 71| r71_4(glval<_Complex float>) = VariableAddress[cf] : # 71| mu71_5(_Complex float) = Store : &:r71_4, r71_3 # 72| r72_1(glval<_Complex long double>) = VariableAddress[cld] : -# 72| r72_2(_Complex long double) = Load : &:r72_1, ~mu58_4 +# 72| r72_2(_Complex long double) = Load : &:r72_1, ~m? # 72| r72_3(_Complex float) = Convert : r72_2 # 72| r72_4(glval<_Complex float>) = VariableAddress[cf] : # 72| mu72_5(_Complex float) = Store : &:r72_4, r72_3 # 73| r73_1(glval<_Complex float>) = VariableAddress[cf] : -# 73| r73_2(_Complex float) = Load : &:r73_1, ~mu58_4 +# 73| r73_2(_Complex float) = Load : &:r73_1, ~m? # 73| r73_3(_Complex double) = Convert : r73_2 # 73| r73_4(glval<_Complex double>) = VariableAddress[cd] : # 73| mu73_5(_Complex double) = Store : &:r73_4, r73_3 # 74| r74_1(glval<_Complex double>) = VariableAddress[cd] : -# 74| r74_2(_Complex double) = Load : &:r74_1, ~mu58_4 +# 74| r74_2(_Complex double) = Load : &:r74_1, ~m? # 74| r74_3(glval<_Complex double>) = VariableAddress[cd] : # 74| mu74_4(_Complex double) = Store : &:r74_3, r74_2 # 75| r75_1(glval<_Complex long double>) = VariableAddress[cld] : -# 75| r75_2(_Complex long double) = Load : &:r75_1, ~mu58_4 +# 75| r75_2(_Complex long double) = Load : &:r75_1, ~m? # 75| r75_3(_Complex double) = Convert : r75_2 # 75| r75_4(glval<_Complex double>) = VariableAddress[cd] : # 75| mu75_5(_Complex double) = Store : &:r75_4, r75_3 # 76| r76_1(glval<_Complex float>) = VariableAddress[cf] : -# 76| r76_2(_Complex float) = Load : &:r76_1, ~mu58_4 +# 76| r76_2(_Complex float) = Load : &:r76_1, ~m? # 76| r76_3(_Complex long double) = Convert : r76_2 # 76| r76_4(glval<_Complex long double>) = VariableAddress[cld] : # 76| mu76_5(_Complex long double) = Store : &:r76_4, r76_3 # 77| r77_1(glval<_Complex double>) = VariableAddress[cd] : -# 77| r77_2(_Complex double) = Load : &:r77_1, ~mu58_4 +# 77| r77_2(_Complex double) = Load : &:r77_1, ~m? # 77| r77_3(_Complex long double) = Convert : r77_2 # 77| r77_4(glval<_Complex long double>) = VariableAddress[cld] : # 77| mu77_5(_Complex long double) = Store : &:r77_4, r77_3 # 78| r78_1(glval<_Complex long double>) = VariableAddress[cld] : -# 78| r78_2(_Complex long double) = Load : &:r78_1, ~mu58_4 +# 78| r78_2(_Complex long double) = Load : &:r78_1, ~m? # 78| r78_3(glval<_Complex long double>) = VariableAddress[cld] : # 78| mu78_4(_Complex long double) = Store : &:r78_3, r78_2 # 81| r81_1(glval) = VariableAddress[f] : -# 81| r81_2(float) = Load : &:r81_1, ~mu58_4 +# 81| r81_2(float) = Load : &:r81_1, ~m? # 81| r81_3(_Complex float) = Convert : r81_2 # 81| r81_4(glval<_Complex float>) = VariableAddress[cf] : # 81| mu81_5(_Complex float) = Store : &:r81_4, r81_3 # 82| r82_1(glval) = VariableAddress[d] : -# 82| r82_2(double) = Load : &:r82_1, ~mu58_4 +# 82| r82_2(double) = Load : &:r82_1, ~m? # 82| r82_3(_Complex float) = Convert : r82_2 # 82| r82_4(glval<_Complex float>) = VariableAddress[cf] : # 82| mu82_5(_Complex float) = Store : &:r82_4, r82_3 # 83| r83_1(glval) = VariableAddress[ld] : -# 83| r83_2(long double) = Load : &:r83_1, ~mu58_4 +# 83| r83_2(long double) = Load : &:r83_1, ~m? # 83| r83_3(_Complex float) = Convert : r83_2 # 83| r83_4(glval<_Complex float>) = VariableAddress[cf] : # 83| mu83_5(_Complex float) = Store : &:r83_4, r83_3 # 84| r84_1(glval) = VariableAddress[f] : -# 84| r84_2(float) = Load : &:r84_1, ~mu58_4 +# 84| r84_2(float) = Load : &:r84_1, ~m? # 84| r84_3(_Complex double) = Convert : r84_2 # 84| r84_4(glval<_Complex double>) = VariableAddress[cd] : # 84| mu84_5(_Complex double) = Store : &:r84_4, r84_3 # 85| r85_1(glval) = VariableAddress[d] : -# 85| r85_2(double) = Load : &:r85_1, ~mu58_4 +# 85| r85_2(double) = Load : &:r85_1, ~m? # 85| r85_3(_Complex double) = Convert : r85_2 # 85| r85_4(glval<_Complex double>) = VariableAddress[cd] : # 85| mu85_5(_Complex double) = Store : &:r85_4, r85_3 # 86| r86_1(glval) = VariableAddress[ld] : -# 86| r86_2(long double) = Load : &:r86_1, ~mu58_4 +# 86| r86_2(long double) = Load : &:r86_1, ~m? # 86| r86_3(_Complex double) = Convert : r86_2 # 86| r86_4(glval<_Complex double>) = VariableAddress[cd] : # 86| mu86_5(_Complex double) = Store : &:r86_4, r86_3 # 87| r87_1(glval) = VariableAddress[f] : -# 87| r87_2(float) = Load : &:r87_1, ~mu58_4 +# 87| r87_2(float) = Load : &:r87_1, ~m? # 87| r87_3(_Complex long double) = Convert : r87_2 # 87| r87_4(glval<_Complex long double>) = VariableAddress[cld] : # 87| mu87_5(_Complex long double) = Store : &:r87_4, r87_3 # 88| r88_1(glval) = VariableAddress[d] : -# 88| r88_2(double) = Load : &:r88_1, ~mu58_4 +# 88| r88_2(double) = Load : &:r88_1, ~m? # 88| r88_3(_Complex long double) = Convert : r88_2 # 88| r88_4(glval<_Complex long double>) = VariableAddress[cld] : # 88| mu88_5(_Complex long double) = Store : &:r88_4, r88_3 # 89| r89_1(glval) = VariableAddress[ld] : -# 89| r89_2(long double) = Load : &:r89_1, ~mu58_4 +# 89| r89_2(long double) = Load : &:r89_1, ~m? # 89| r89_3(_Complex long double) = Convert : r89_2 # 89| r89_4(glval<_Complex long double>) = VariableAddress[cld] : # 89| mu89_5(_Complex long double) = Store : &:r89_4, r89_3 # 92| r92_1(glval<_Complex float>) = VariableAddress[cf] : -# 92| r92_2(_Complex float) = Load : &:r92_1, ~mu58_4 +# 92| r92_2(_Complex float) = Load : &:r92_1, ~m? # 92| r92_3(float) = Convert : r92_2 # 92| r92_4(glval) = VariableAddress[f] : # 92| mu92_5(float) = Store : &:r92_4, r92_3 # 93| r93_1(glval<_Complex double>) = VariableAddress[cd] : -# 93| r93_2(_Complex double) = Load : &:r93_1, ~mu58_4 +# 93| r93_2(_Complex double) = Load : &:r93_1, ~m? # 93| r93_3(float) = Convert : r93_2 # 93| r93_4(glval) = VariableAddress[f] : # 93| mu93_5(float) = Store : &:r93_4, r93_3 # 94| r94_1(glval<_Complex long double>) = VariableAddress[cld] : -# 94| r94_2(_Complex long double) = Load : &:r94_1, ~mu58_4 +# 94| r94_2(_Complex long double) = Load : &:r94_1, ~m? # 94| r94_3(float) = Convert : r94_2 # 94| r94_4(glval) = VariableAddress[f] : # 94| mu94_5(float) = Store : &:r94_4, r94_3 # 95| r95_1(glval<_Complex float>) = VariableAddress[cf] : -# 95| r95_2(_Complex float) = Load : &:r95_1, ~mu58_4 +# 95| r95_2(_Complex float) = Load : &:r95_1, ~m? # 95| r95_3(double) = Convert : r95_2 # 95| r95_4(glval) = VariableAddress[d] : # 95| mu95_5(double) = Store : &:r95_4, r95_3 # 96| r96_1(glval<_Complex double>) = VariableAddress[cd] : -# 96| r96_2(_Complex double) = Load : &:r96_1, ~mu58_4 +# 96| r96_2(_Complex double) = Load : &:r96_1, ~m? # 96| r96_3(double) = Convert : r96_2 # 96| r96_4(glval) = VariableAddress[d] : # 96| mu96_5(double) = Store : &:r96_4, r96_3 # 97| r97_1(glval<_Complex long double>) = VariableAddress[cld] : -# 97| r97_2(_Complex long double) = Load : &:r97_1, ~mu58_4 +# 97| r97_2(_Complex long double) = Load : &:r97_1, ~m? # 97| r97_3(double) = Convert : r97_2 # 97| r97_4(glval) = VariableAddress[d] : # 97| mu97_5(double) = Store : &:r97_4, r97_3 # 98| r98_1(glval<_Complex float>) = VariableAddress[cf] : -# 98| r98_2(_Complex float) = Load : &:r98_1, ~mu58_4 +# 98| r98_2(_Complex float) = Load : &:r98_1, ~m? # 98| r98_3(long double) = Convert : r98_2 # 98| r98_4(glval) = VariableAddress[ld] : # 98| mu98_5(long double) = Store : &:r98_4, r98_3 # 99| r99_1(glval<_Complex double>) = VariableAddress[cd] : -# 99| r99_2(_Complex double) = Load : &:r99_1, ~mu58_4 +# 99| r99_2(_Complex double) = Load : &:r99_1, ~m? # 99| r99_3(long double) = Convert : r99_2 # 99| r99_4(glval) = VariableAddress[ld] : # 99| mu99_5(long double) = Store : &:r99_4, r99_3 # 100| r100_1(glval<_Complex long double>) = VariableAddress[cld] : -# 100| r100_2(_Complex long double) = Load : &:r100_1, ~mu58_4 +# 100| r100_2(_Complex long double) = Load : &:r100_1, ~m? # 100| r100_3(long double) = Convert : r100_2 # 100| r100_4(glval) = VariableAddress[ld] : # 100| mu100_5(long double) = Store : &:r100_4, r100_3 # 103| r103_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~mu58_4 +# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~m? # 103| r103_3(_Complex float) = Convert : r103_2 # 103| r103_4(glval<_Complex float>) = VariableAddress[cf] : # 103| mu103_5(_Complex float) = Store : &:r103_4, r103_3 # 104| r104_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~mu58_4 +# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~m? # 104| r104_3(_Complex float) = Convert : r104_2 # 104| r104_4(glval<_Complex float>) = VariableAddress[cf] : # 104| mu104_5(_Complex float) = Store : &:r104_4, r104_3 # 105| r105_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~mu58_4 +# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~m? # 105| r105_3(_Complex float) = Convert : r105_2 # 105| r105_4(glval<_Complex float>) = VariableAddress[cf] : # 105| mu105_5(_Complex float) = Store : &:r105_4, r105_3 # 106| r106_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~mu58_4 +# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~m? # 106| r106_3(_Complex double) = Convert : r106_2 # 106| r106_4(glval<_Complex double>) = VariableAddress[cd] : # 106| mu106_5(_Complex double) = Store : &:r106_4, r106_3 # 107| r107_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~mu58_4 +# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~m? # 107| r107_3(_Complex double) = Convert : r107_2 # 107| r107_4(glval<_Complex double>) = VariableAddress[cd] : # 107| mu107_5(_Complex double) = Store : &:r107_4, r107_3 # 108| r108_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~mu58_4 +# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~m? # 108| r108_3(_Complex double) = Convert : r108_2 # 108| r108_4(glval<_Complex double>) = VariableAddress[cd] : # 108| mu108_5(_Complex double) = Store : &:r108_4, r108_3 # 109| r109_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~mu58_4 +# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~m? # 109| r109_3(_Complex long double) = Convert : r109_2 # 109| r109_4(glval<_Complex long double>) = VariableAddress[cld] : # 109| mu109_5(_Complex long double) = Store : &:r109_4, r109_3 # 110| r110_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~mu58_4 +# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~m? # 110| r110_3(_Complex long double) = Convert : r110_2 # 110| r110_4(glval<_Complex long double>) = VariableAddress[cld] : # 110| mu110_5(_Complex long double) = Store : &:r110_4, r110_3 # 111| r111_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~mu58_4 +# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~m? # 111| r111_3(_Complex long double) = Convert : r111_2 # 111| r111_4(glval<_Complex long double>) = VariableAddress[cld] : # 111| mu111_5(_Complex long double) = Store : &:r111_4, r111_3 # 114| r114_1(glval<_Complex float>) = VariableAddress[cf] : -# 114| r114_2(_Complex float) = Load : &:r114_1, ~mu58_4 +# 114| r114_2(_Complex float) = Load : &:r114_1, ~m? # 114| r114_3(_Imaginary float) = Convert : r114_2 # 114| r114_4(glval<_Imaginary float>) = VariableAddress[jf] : # 114| mu114_5(_Imaginary float) = Store : &:r114_4, r114_3 # 115| r115_1(glval<_Complex double>) = VariableAddress[cd] : -# 115| r115_2(_Complex double) = Load : &:r115_1, ~mu58_4 +# 115| r115_2(_Complex double) = Load : &:r115_1, ~m? # 115| r115_3(_Imaginary float) = Convert : r115_2 # 115| r115_4(glval<_Imaginary float>) = VariableAddress[jf] : # 115| mu115_5(_Imaginary float) = Store : &:r115_4, r115_3 # 116| r116_1(glval<_Complex long double>) = VariableAddress[cld] : -# 116| r116_2(_Complex long double) = Load : &:r116_1, ~mu58_4 +# 116| r116_2(_Complex long double) = Load : &:r116_1, ~m? # 116| r116_3(_Imaginary float) = Convert : r116_2 # 116| r116_4(glval<_Imaginary float>) = VariableAddress[jf] : # 116| mu116_5(_Imaginary float) = Store : &:r116_4, r116_3 # 117| r117_1(glval<_Complex float>) = VariableAddress[cf] : -# 117| r117_2(_Complex float) = Load : &:r117_1, ~mu58_4 +# 117| r117_2(_Complex float) = Load : &:r117_1, ~m? # 117| r117_3(_Imaginary double) = Convert : r117_2 # 117| r117_4(glval<_Imaginary double>) = VariableAddress[jd] : # 117| mu117_5(_Imaginary double) = Store : &:r117_4, r117_3 # 118| r118_1(glval<_Complex double>) = VariableAddress[cd] : -# 118| r118_2(_Complex double) = Load : &:r118_1, ~mu58_4 +# 118| r118_2(_Complex double) = Load : &:r118_1, ~m? # 118| r118_3(_Imaginary double) = Convert : r118_2 # 118| r118_4(glval<_Imaginary double>) = VariableAddress[jd] : # 118| mu118_5(_Imaginary double) = Store : &:r118_4, r118_3 # 119| r119_1(glval<_Complex long double>) = VariableAddress[cld] : -# 119| r119_2(_Complex long double) = Load : &:r119_1, ~mu58_4 +# 119| r119_2(_Complex long double) = Load : &:r119_1, ~m? # 119| r119_3(_Imaginary double) = Convert : r119_2 # 119| r119_4(glval<_Imaginary double>) = VariableAddress[jd] : # 119| mu119_5(_Imaginary double) = Store : &:r119_4, r119_3 # 120| r120_1(glval<_Complex float>) = VariableAddress[cf] : -# 120| r120_2(_Complex float) = Load : &:r120_1, ~mu58_4 +# 120| r120_2(_Complex float) = Load : &:r120_1, ~m? # 120| r120_3(_Imaginary long double) = Convert : r120_2 # 120| r120_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 120| mu120_5(_Imaginary long double) = Store : &:r120_4, r120_3 # 121| r121_1(glval<_Complex double>) = VariableAddress[cd] : -# 121| r121_2(_Complex double) = Load : &:r121_1, ~mu58_4 +# 121| r121_2(_Complex double) = Load : &:r121_1, ~m? # 121| r121_3(_Imaginary long double) = Convert : r121_2 # 121| r121_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 121| mu121_5(_Imaginary long double) = Store : &:r121_4, r121_3 # 122| r122_1(glval<_Complex long double>) = VariableAddress[cld] : -# 122| r122_2(_Complex long double) = Load : &:r122_1, ~mu58_4 +# 122| r122_2(_Complex long double) = Load : &:r122_1, ~m? # 122| r122_3(_Imaginary long double) = Convert : r122_2 # 122| r122_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 122| mu122_5(_Imaginary long double) = Store : &:r122_4, r122_3 # 125| r125_1(glval) = VariableAddress[f] : -# 125| r125_2(float) = Load : &:r125_1, ~mu58_4 +# 125| r125_2(float) = Load : &:r125_1, ~m? # 125| r125_3(_Imaginary float) = Convert : r125_2 # 125| r125_4(glval<_Imaginary float>) = VariableAddress[jf] : # 125| mu125_5(_Imaginary float) = Store : &:r125_4, r125_3 # 126| r126_1(glval) = VariableAddress[d] : -# 126| r126_2(double) = Load : &:r126_1, ~mu58_4 +# 126| r126_2(double) = Load : &:r126_1, ~m? # 126| r126_3(_Imaginary float) = Convert : r126_2 # 126| r126_4(glval<_Imaginary float>) = VariableAddress[jf] : # 126| mu126_5(_Imaginary float) = Store : &:r126_4, r126_3 # 127| r127_1(glval) = VariableAddress[ld] : -# 127| r127_2(long double) = Load : &:r127_1, ~mu58_4 +# 127| r127_2(long double) = Load : &:r127_1, ~m? # 127| r127_3(_Imaginary float) = Convert : r127_2 # 127| r127_4(glval<_Imaginary float>) = VariableAddress[jf] : # 127| mu127_5(_Imaginary float) = Store : &:r127_4, r127_3 # 128| r128_1(glval) = VariableAddress[f] : -# 128| r128_2(float) = Load : &:r128_1, ~mu58_4 +# 128| r128_2(float) = Load : &:r128_1, ~m? # 128| r128_3(_Imaginary double) = Convert : r128_2 # 128| r128_4(glval<_Imaginary double>) = VariableAddress[jd] : # 128| mu128_5(_Imaginary double) = Store : &:r128_4, r128_3 # 129| r129_1(glval) = VariableAddress[d] : -# 129| r129_2(double) = Load : &:r129_1, ~mu58_4 +# 129| r129_2(double) = Load : &:r129_1, ~m? # 129| r129_3(_Imaginary double) = Convert : r129_2 # 129| r129_4(glval<_Imaginary double>) = VariableAddress[jd] : # 129| mu129_5(_Imaginary double) = Store : &:r129_4, r129_3 # 130| r130_1(glval) = VariableAddress[ld] : -# 130| r130_2(long double) = Load : &:r130_1, ~mu58_4 +# 130| r130_2(long double) = Load : &:r130_1, ~m? # 130| r130_3(_Imaginary double) = Convert : r130_2 # 130| r130_4(glval<_Imaginary double>) = VariableAddress[jd] : # 130| mu130_5(_Imaginary double) = Store : &:r130_4, r130_3 # 131| r131_1(glval) = VariableAddress[f] : -# 131| r131_2(float) = Load : &:r131_1, ~mu58_4 +# 131| r131_2(float) = Load : &:r131_1, ~m? # 131| r131_3(_Imaginary long double) = Convert : r131_2 # 131| r131_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 131| mu131_5(_Imaginary long double) = Store : &:r131_4, r131_3 # 132| r132_1(glval) = VariableAddress[d] : -# 132| r132_2(double) = Load : &:r132_1, ~mu58_4 +# 132| r132_2(double) = Load : &:r132_1, ~m? # 132| r132_3(_Imaginary long double) = Convert : r132_2 # 132| r132_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 132| mu132_5(_Imaginary long double) = Store : &:r132_4, r132_3 # 133| r133_1(glval) = VariableAddress[ld] : -# 133| r133_2(long double) = Load : &:r133_1, ~mu58_4 +# 133| r133_2(long double) = Load : &:r133_1, ~m? # 133| r133_3(_Imaginary long double) = Convert : r133_2 # 133| r133_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 133| mu133_5(_Imaginary long double) = Store : &:r133_4, r133_3 # 136| r136_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~mu58_4 +# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~m? # 136| r136_3(float) = Convert : r136_2 # 136| r136_4(glval) = VariableAddress[f] : # 136| mu136_5(float) = Store : &:r136_4, r136_3 # 137| r137_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~mu58_4 +# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~m? # 137| r137_3(float) = Convert : r137_2 # 137| r137_4(glval) = VariableAddress[f] : # 137| mu137_5(float) = Store : &:r137_4, r137_3 # 138| r138_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~mu58_4 +# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~m? # 138| r138_3(float) = Convert : r138_2 # 138| r138_4(glval) = VariableAddress[f] : # 138| mu138_5(float) = Store : &:r138_4, r138_3 # 139| r139_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~mu58_4 +# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~m? # 139| r139_3(double) = Convert : r139_2 # 139| r139_4(glval) = VariableAddress[d] : # 139| mu139_5(double) = Store : &:r139_4, r139_3 # 140| r140_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~mu58_4 +# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~m? # 140| r140_3(double) = Convert : r140_2 # 140| r140_4(glval) = VariableAddress[d] : # 140| mu140_5(double) = Store : &:r140_4, r140_3 # 141| r141_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~mu58_4 +# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~m? # 141| r141_3(double) = Convert : r141_2 # 141| r141_4(glval) = VariableAddress[d] : # 141| mu141_5(double) = Store : &:r141_4, r141_3 # 142| r142_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~mu58_4 +# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~m? # 142| r142_3(long double) = Convert : r142_2 # 142| r142_4(glval) = VariableAddress[ld] : # 142| mu142_5(long double) = Store : &:r142_4, r142_3 # 143| r143_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~mu58_4 +# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~m? # 143| r143_3(long double) = Convert : r143_2 # 143| r143_4(glval) = VariableAddress[ld] : # 143| mu143_5(long double) = Store : &:r143_4, r143_3 # 144| r144_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~mu58_4 +# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~m? # 144| r144_3(long double) = Convert : r144_2 # 144| r144_4(glval) = VariableAddress[ld] : # 144| mu144_5(long double) = Store : &:r144_4, r144_3 # 145| v145_1(void) = NoOp : -# 58| v58_5(void) = ReturnVoid : -# 58| v58_6(void) = UnmodeledUse : mu* -# 58| v58_7(void) = AliasedUse : ~mu58_4 -# 58| v58_8(void) = ExitFunction : +# 58| v58_4(void) = ReturnVoid : +# 58| v58_5(void) = AliasedUse : ~m? +# 58| v58_6(void) = ExitFunction : ir.cpp: # 1| void Constants() @@ -704,7 +695,6 @@ ir.cpp: # 1| v1_1(void) = EnterFunction : # 1| mu1_2(unknown) = AliasedDefinition : # 1| mu1_3(unknown) = InitializeNonLocal : -# 1| mu1_4(unknown) = UnmodeledDefinition : # 2| r2_1(glval) = VariableAddress[c_i] : # 2| r2_2(char) = Constant[1] : # 2| mu2_3(char) = Store : &:r2_1, r2_2 @@ -790,209 +780,205 @@ ir.cpp: # 40| r40_2(double) = Constant[1.0] : # 40| mu40_3(double) = Store : &:r40_1, r40_2 # 41| v41_1(void) = NoOp : -# 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = UnmodeledUse : mu* -# 1| v1_7(void) = AliasedUse : ~mu1_4 -# 1| v1_8(void) = ExitFunction : +# 1| v1_4(void) = ReturnVoid : +# 1| v1_5(void) = AliasedUse : ~m? +# 1| v1_6(void) = ExitFunction : # 43| void Foo() # 43| Block 0 -# 43| v43_1(void) = EnterFunction : -# 43| mu43_2(unknown) = AliasedDefinition : -# 43| mu43_3(unknown) = InitializeNonLocal : -# 43| mu43_4(unknown) = UnmodeledDefinition : -# 44| r44_1(glval) = VariableAddress[x] : -# 44| r44_2(int) = Constant[17] : -# 44| mu44_3(int) = Store : &:r44_1, r44_2 -# 45| r45_1(glval) = VariableAddress[y] : -# 45| r45_2(short) = Constant[7] : -# 45| mu45_3(short) = Store : &:r45_1, r45_2 -# 46| r46_1(glval) = VariableAddress[x] : -# 46| r46_2(int) = Load : &:r46_1, ~mu43_4 -# 46| r46_3(glval) = VariableAddress[y] : -# 46| r46_4(short) = Load : &:r46_3, ~mu43_4 -# 46| r46_5(int) = Convert : r46_4 -# 46| r46_6(int) = Add : r46_2, r46_5 -# 46| r46_7(short) = Convert : r46_6 -# 46| r46_8(glval) = VariableAddress[y] : -# 46| mu46_9(short) = Store : &:r46_8, r46_7 -# 47| r47_1(glval) = VariableAddress[x] : -# 47| r47_2(int) = Load : &:r47_1, ~mu43_4 -# 47| r47_3(glval) = VariableAddress[y] : -# 47| r47_4(short) = Load : &:r47_3, ~mu43_4 -# 47| r47_5(int) = Convert : r47_4 -# 47| r47_6(int) = Mul : r47_2, r47_5 -# 47| r47_7(glval) = VariableAddress[x] : -# 47| mu47_8(int) = Store : &:r47_7, r47_6 -# 48| v48_1(void) = NoOp : -# 43| v43_5(void) = ReturnVoid : -# 43| v43_6(void) = UnmodeledUse : mu* -# 43| v43_7(void) = AliasedUse : ~mu43_4 -# 43| v43_8(void) = ExitFunction : +# 43| v43_1(void) = EnterFunction : +# 43| mu43_2(unknown) = AliasedDefinition : +# 43| mu43_3(unknown) = InitializeNonLocal : +# 44| r44_1(glval) = VariableAddress[x] : +# 44| r44_2(int) = Constant[17] : +# 44| mu44_3(int) = Store : &:r44_1, r44_2 +# 45| r45_1(glval) = VariableAddress[y] : +# 45| r45_2(short) = Constant[7] : +# 45| mu45_3(short) = Store : &:r45_1, r45_2 +# 46| r46_1(glval) = VariableAddress[x] : +# 46| r46_2(int) = Load : &:r46_1, ~m? +# 46| r46_3(glval) = VariableAddress[y] : +# 46| r46_4(short) = Load : &:r46_3, ~m? +# 46| r46_5(int) = Convert : r46_4 +# 46| r46_6(int) = Add : r46_2, r46_5 +# 46| r46_7(short) = Convert : r46_6 +# 46| r46_8(glval) = VariableAddress[y] : +# 46| mu46_9(short) = Store : &:r46_8, r46_7 +# 47| r47_1(glval) = VariableAddress[x] : +# 47| r47_2(int) = Load : &:r47_1, ~m? +# 47| r47_3(glval) = VariableAddress[y] : +# 47| r47_4(short) = Load : &:r47_3, ~m? +# 47| r47_5(int) = Convert : r47_4 +# 47| r47_6(int) = Mul : r47_2, r47_5 +# 47| r47_7(glval) = VariableAddress[x] : +# 47| mu47_8(int) = Store : &:r47_7, r47_6 +# 48| v48_1(void) = NoOp : +# 43| v43_4(void) = ReturnVoid : +# 43| v43_5(void) = AliasedUse : ~m? +# 43| v43_6(void) = ExitFunction : # 50| void IntegerOps(int, int) # 50| Block 0 # 50| v50_1(void) = EnterFunction : # 50| mu50_2(unknown) = AliasedDefinition : # 50| mu50_3(unknown) = InitializeNonLocal : -# 50| mu50_4(unknown) = UnmodeledDefinition : -# 50| r50_5(glval) = VariableAddress[x] : -# 50| mu50_6(int) = InitializeParameter[x] : &:r50_5 -# 50| r50_7(glval) = VariableAddress[y] : -# 50| mu50_8(int) = InitializeParameter[y] : &:r50_7 +# 50| r50_4(glval) = VariableAddress[x] : +# 50| mu50_5(int) = InitializeParameter[x] : &:r50_4 +# 50| r50_6(glval) = VariableAddress[y] : +# 50| mu50_7(int) = InitializeParameter[y] : &:r50_6 # 51| r51_1(glval) = VariableAddress[z] : # 51| mu51_2(int) = Uninitialized[z] : &:r51_1 # 53| r53_1(glval) = VariableAddress[x] : -# 53| r53_2(int) = Load : &:r53_1, ~mu50_4 +# 53| r53_2(int) = Load : &:r53_1, ~m? # 53| r53_3(glval) = VariableAddress[y] : -# 53| r53_4(int) = Load : &:r53_3, ~mu50_4 +# 53| r53_4(int) = Load : &:r53_3, ~m? # 53| r53_5(int) = Add : r53_2, r53_4 # 53| r53_6(glval) = VariableAddress[z] : # 53| mu53_7(int) = Store : &:r53_6, r53_5 # 54| r54_1(glval) = VariableAddress[x] : -# 54| r54_2(int) = Load : &:r54_1, ~mu50_4 +# 54| r54_2(int) = Load : &:r54_1, ~m? # 54| r54_3(glval) = VariableAddress[y] : -# 54| r54_4(int) = Load : &:r54_3, ~mu50_4 +# 54| r54_4(int) = Load : &:r54_3, ~m? # 54| r54_5(int) = Sub : r54_2, r54_4 # 54| r54_6(glval) = VariableAddress[z] : # 54| mu54_7(int) = Store : &:r54_6, r54_5 # 55| r55_1(glval) = VariableAddress[x] : -# 55| r55_2(int) = Load : &:r55_1, ~mu50_4 +# 55| r55_2(int) = Load : &:r55_1, ~m? # 55| r55_3(glval) = VariableAddress[y] : -# 55| r55_4(int) = Load : &:r55_3, ~mu50_4 +# 55| r55_4(int) = Load : &:r55_3, ~m? # 55| r55_5(int) = Mul : r55_2, r55_4 # 55| r55_6(glval) = VariableAddress[z] : # 55| mu55_7(int) = Store : &:r55_6, r55_5 # 56| r56_1(glval) = VariableAddress[x] : -# 56| r56_2(int) = Load : &:r56_1, ~mu50_4 +# 56| r56_2(int) = Load : &:r56_1, ~m? # 56| r56_3(glval) = VariableAddress[y] : -# 56| r56_4(int) = Load : &:r56_3, ~mu50_4 +# 56| r56_4(int) = Load : &:r56_3, ~m? # 56| r56_5(int) = Div : r56_2, r56_4 # 56| r56_6(glval) = VariableAddress[z] : # 56| mu56_7(int) = Store : &:r56_6, r56_5 # 57| r57_1(glval) = VariableAddress[x] : -# 57| r57_2(int) = Load : &:r57_1, ~mu50_4 +# 57| r57_2(int) = Load : &:r57_1, ~m? # 57| r57_3(glval) = VariableAddress[y] : -# 57| r57_4(int) = Load : &:r57_3, ~mu50_4 +# 57| r57_4(int) = Load : &:r57_3, ~m? # 57| r57_5(int) = Rem : r57_2, r57_4 # 57| r57_6(glval) = VariableAddress[z] : # 57| mu57_7(int) = Store : &:r57_6, r57_5 # 59| r59_1(glval) = VariableAddress[x] : -# 59| r59_2(int) = Load : &:r59_1, ~mu50_4 +# 59| r59_2(int) = Load : &:r59_1, ~m? # 59| r59_3(glval) = VariableAddress[y] : -# 59| r59_4(int) = Load : &:r59_3, ~mu50_4 +# 59| r59_4(int) = Load : &:r59_3, ~m? # 59| r59_5(int) = BitAnd : r59_2, r59_4 # 59| r59_6(glval) = VariableAddress[z] : # 59| mu59_7(int) = Store : &:r59_6, r59_5 # 60| r60_1(glval) = VariableAddress[x] : -# 60| r60_2(int) = Load : &:r60_1, ~mu50_4 +# 60| r60_2(int) = Load : &:r60_1, ~m? # 60| r60_3(glval) = VariableAddress[y] : -# 60| r60_4(int) = Load : &:r60_3, ~mu50_4 +# 60| r60_4(int) = Load : &:r60_3, ~m? # 60| r60_5(int) = BitOr : r60_2, r60_4 # 60| r60_6(glval) = VariableAddress[z] : # 60| mu60_7(int) = Store : &:r60_6, r60_5 # 61| r61_1(glval) = VariableAddress[x] : -# 61| r61_2(int) = Load : &:r61_1, ~mu50_4 +# 61| r61_2(int) = Load : &:r61_1, ~m? # 61| r61_3(glval) = VariableAddress[y] : -# 61| r61_4(int) = Load : &:r61_3, ~mu50_4 +# 61| r61_4(int) = Load : &:r61_3, ~m? # 61| r61_5(int) = BitXor : r61_2, r61_4 # 61| r61_6(glval) = VariableAddress[z] : # 61| mu61_7(int) = Store : &:r61_6, r61_5 # 63| r63_1(glval) = VariableAddress[x] : -# 63| r63_2(int) = Load : &:r63_1, ~mu50_4 +# 63| r63_2(int) = Load : &:r63_1, ~m? # 63| r63_3(glval) = VariableAddress[y] : -# 63| r63_4(int) = Load : &:r63_3, ~mu50_4 +# 63| r63_4(int) = Load : &:r63_3, ~m? # 63| r63_5(int) = ShiftLeft : r63_2, r63_4 # 63| r63_6(glval) = VariableAddress[z] : # 63| mu63_7(int) = Store : &:r63_6, r63_5 # 64| r64_1(glval) = VariableAddress[x] : -# 64| r64_2(int) = Load : &:r64_1, ~mu50_4 +# 64| r64_2(int) = Load : &:r64_1, ~m? # 64| r64_3(glval) = VariableAddress[y] : -# 64| r64_4(int) = Load : &:r64_3, ~mu50_4 +# 64| r64_4(int) = Load : &:r64_3, ~m? # 64| r64_5(int) = ShiftRight : r64_2, r64_4 # 64| r64_6(glval) = VariableAddress[z] : # 64| mu64_7(int) = Store : &:r64_6, r64_5 # 66| r66_1(glval) = VariableAddress[x] : -# 66| r66_2(int) = Load : &:r66_1, ~mu50_4 +# 66| r66_2(int) = Load : &:r66_1, ~m? # 66| r66_3(glval) = VariableAddress[z] : # 66| mu66_4(int) = Store : &:r66_3, r66_2 # 68| r68_1(glval) = VariableAddress[x] : -# 68| r68_2(int) = Load : &:r68_1, ~mu50_4 +# 68| r68_2(int) = Load : &:r68_1, ~m? # 68| r68_3(glval) = VariableAddress[z] : -# 68| r68_4(int) = Load : &:r68_3, ~mu50_4 +# 68| r68_4(int) = Load : &:r68_3, ~m? # 68| r68_5(int) = Add : r68_4, r68_2 # 68| mu68_6(int) = Store : &:r68_3, r68_5 # 69| r69_1(glval) = VariableAddress[x] : -# 69| r69_2(int) = Load : &:r69_1, ~mu50_4 +# 69| r69_2(int) = Load : &:r69_1, ~m? # 69| r69_3(glval) = VariableAddress[z] : -# 69| r69_4(int) = Load : &:r69_3, ~mu50_4 +# 69| r69_4(int) = Load : &:r69_3, ~m? # 69| r69_5(int) = Sub : r69_4, r69_2 # 69| mu69_6(int) = Store : &:r69_3, r69_5 # 70| r70_1(glval) = VariableAddress[x] : -# 70| r70_2(int) = Load : &:r70_1, ~mu50_4 +# 70| r70_2(int) = Load : &:r70_1, ~m? # 70| r70_3(glval) = VariableAddress[z] : -# 70| r70_4(int) = Load : &:r70_3, ~mu50_4 +# 70| r70_4(int) = Load : &:r70_3, ~m? # 70| r70_5(int) = Mul : r70_4, r70_2 # 70| mu70_6(int) = Store : &:r70_3, r70_5 # 71| r71_1(glval) = VariableAddress[x] : -# 71| r71_2(int) = Load : &:r71_1, ~mu50_4 +# 71| r71_2(int) = Load : &:r71_1, ~m? # 71| r71_3(glval) = VariableAddress[z] : -# 71| r71_4(int) = Load : &:r71_3, ~mu50_4 +# 71| r71_4(int) = Load : &:r71_3, ~m? # 71| r71_5(int) = Div : r71_4, r71_2 # 71| mu71_6(int) = Store : &:r71_3, r71_5 # 72| r72_1(glval) = VariableAddress[x] : -# 72| r72_2(int) = Load : &:r72_1, ~mu50_4 +# 72| r72_2(int) = Load : &:r72_1, ~m? # 72| r72_3(glval) = VariableAddress[z] : -# 72| r72_4(int) = Load : &:r72_3, ~mu50_4 +# 72| r72_4(int) = Load : &:r72_3, ~m? # 72| r72_5(int) = Rem : r72_4, r72_2 # 72| mu72_6(int) = Store : &:r72_3, r72_5 # 74| r74_1(glval) = VariableAddress[x] : -# 74| r74_2(int) = Load : &:r74_1, ~mu50_4 +# 74| r74_2(int) = Load : &:r74_1, ~m? # 74| r74_3(glval) = VariableAddress[z] : -# 74| r74_4(int) = Load : &:r74_3, ~mu50_4 +# 74| r74_4(int) = Load : &:r74_3, ~m? # 74| r74_5(int) = BitAnd : r74_4, r74_2 # 74| mu74_6(int) = Store : &:r74_3, r74_5 # 75| r75_1(glval) = VariableAddress[x] : -# 75| r75_2(int) = Load : &:r75_1, ~mu50_4 +# 75| r75_2(int) = Load : &:r75_1, ~m? # 75| r75_3(glval) = VariableAddress[z] : -# 75| r75_4(int) = Load : &:r75_3, ~mu50_4 +# 75| r75_4(int) = Load : &:r75_3, ~m? # 75| r75_5(int) = BitOr : r75_4, r75_2 # 75| mu75_6(int) = Store : &:r75_3, r75_5 # 76| r76_1(glval) = VariableAddress[x] : -# 76| r76_2(int) = Load : &:r76_1, ~mu50_4 +# 76| r76_2(int) = Load : &:r76_1, ~m? # 76| r76_3(glval) = VariableAddress[z] : -# 76| r76_4(int) = Load : &:r76_3, ~mu50_4 +# 76| r76_4(int) = Load : &:r76_3, ~m? # 76| r76_5(int) = BitXor : r76_4, r76_2 # 76| mu76_6(int) = Store : &:r76_3, r76_5 # 78| r78_1(glval) = VariableAddress[x] : -# 78| r78_2(int) = Load : &:r78_1, ~mu50_4 +# 78| r78_2(int) = Load : &:r78_1, ~m? # 78| r78_3(glval) = VariableAddress[z] : -# 78| r78_4(int) = Load : &:r78_3, ~mu50_4 +# 78| r78_4(int) = Load : &:r78_3, ~m? # 78| r78_5(int) = ShiftLeft : r78_4, r78_2 # 78| mu78_6(int) = Store : &:r78_3, r78_5 # 79| r79_1(glval) = VariableAddress[x] : -# 79| r79_2(int) = Load : &:r79_1, ~mu50_4 +# 79| r79_2(int) = Load : &:r79_1, ~m? # 79| r79_3(glval) = VariableAddress[z] : -# 79| r79_4(int) = Load : &:r79_3, ~mu50_4 +# 79| r79_4(int) = Load : &:r79_3, ~m? # 79| r79_5(int) = ShiftRight : r79_4, r79_2 # 79| mu79_6(int) = Store : &:r79_3, r79_5 # 81| r81_1(glval) = VariableAddress[x] : -# 81| r81_2(int) = Load : &:r81_1, ~mu50_4 +# 81| r81_2(int) = Load : &:r81_1, ~m? # 81| r81_3(int) = CopyValue : r81_2 # 81| r81_4(glval) = VariableAddress[z] : # 81| mu81_5(int) = Store : &:r81_4, r81_3 # 82| r82_1(glval) = VariableAddress[x] : -# 82| r82_2(int) = Load : &:r82_1, ~mu50_4 +# 82| r82_2(int) = Load : &:r82_1, ~m? # 82| r82_3(int) = Negate : r82_2 # 82| r82_4(glval) = VariableAddress[z] : # 82| mu82_5(int) = Store : &:r82_4, r82_3 # 83| r83_1(glval) = VariableAddress[x] : -# 83| r83_2(int) = Load : &:r83_1, ~mu50_4 +# 83| r83_2(int) = Load : &:r83_1, ~m? # 83| r83_3(int) = BitComplement : r83_2 # 83| r83_4(glval) = VariableAddress[z] : # 83| mu83_5(int) = Store : &:r83_4, r83_3 # 84| r84_1(glval) = VariableAddress[x] : -# 84| r84_2(int) = Load : &:r84_1, ~mu50_4 +# 84| r84_2(int) = Load : &:r84_1, ~m? # 84| r84_3(int) = Constant[0] : # 84| r84_4(bool) = CompareNE : r84_2, r84_3 # 84| r84_5(bool) = LogicalNot : r84_4 @@ -1000,97 +986,93 @@ ir.cpp: # 84| r84_7(glval) = VariableAddress[z] : # 84| mu84_8(int) = Store : &:r84_7, r84_6 # 85| v85_1(void) = NoOp : -# 50| v50_9(void) = ReturnVoid : -# 50| v50_10(void) = UnmodeledUse : mu* -# 50| v50_11(void) = AliasedUse : ~mu50_4 -# 50| v50_12(void) = ExitFunction : +# 50| v50_8(void) = ReturnVoid : +# 50| v50_9(void) = AliasedUse : ~m? +# 50| v50_10(void) = ExitFunction : # 87| void IntegerCompare(int, int) # 87| Block 0 # 87| v87_1(void) = EnterFunction : # 87| mu87_2(unknown) = AliasedDefinition : # 87| mu87_3(unknown) = InitializeNonLocal : -# 87| mu87_4(unknown) = UnmodeledDefinition : -# 87| r87_5(glval) = VariableAddress[x] : -# 87| mu87_6(int) = InitializeParameter[x] : &:r87_5 -# 87| r87_7(glval) = VariableAddress[y] : -# 87| mu87_8(int) = InitializeParameter[y] : &:r87_7 +# 87| r87_4(glval) = VariableAddress[x] : +# 87| mu87_5(int) = InitializeParameter[x] : &:r87_4 +# 87| r87_6(glval) = VariableAddress[y] : +# 87| mu87_7(int) = InitializeParameter[y] : &:r87_6 # 88| r88_1(glval) = VariableAddress[b] : # 88| mu88_2(bool) = Uninitialized[b] : &:r88_1 # 90| r90_1(glval) = VariableAddress[x] : -# 90| r90_2(int) = Load : &:r90_1, ~mu87_4 +# 90| r90_2(int) = Load : &:r90_1, ~m? # 90| r90_3(glval) = VariableAddress[y] : -# 90| r90_4(int) = Load : &:r90_3, ~mu87_4 +# 90| r90_4(int) = Load : &:r90_3, ~m? # 90| r90_5(bool) = CompareEQ : r90_2, r90_4 # 90| r90_6(glval) = VariableAddress[b] : # 90| mu90_7(bool) = Store : &:r90_6, r90_5 # 91| r91_1(glval) = VariableAddress[x] : -# 91| r91_2(int) = Load : &:r91_1, ~mu87_4 +# 91| r91_2(int) = Load : &:r91_1, ~m? # 91| r91_3(glval) = VariableAddress[y] : -# 91| r91_4(int) = Load : &:r91_3, ~mu87_4 +# 91| r91_4(int) = Load : &:r91_3, ~m? # 91| r91_5(bool) = CompareNE : r91_2, r91_4 # 91| r91_6(glval) = VariableAddress[b] : # 91| mu91_7(bool) = Store : &:r91_6, r91_5 # 92| r92_1(glval) = VariableAddress[x] : -# 92| r92_2(int) = Load : &:r92_1, ~mu87_4 +# 92| r92_2(int) = Load : &:r92_1, ~m? # 92| r92_3(glval) = VariableAddress[y] : -# 92| r92_4(int) = Load : &:r92_3, ~mu87_4 +# 92| r92_4(int) = Load : &:r92_3, ~m? # 92| r92_5(bool) = CompareLT : r92_2, r92_4 # 92| r92_6(glval) = VariableAddress[b] : # 92| mu92_7(bool) = Store : &:r92_6, r92_5 # 93| r93_1(glval) = VariableAddress[x] : -# 93| r93_2(int) = Load : &:r93_1, ~mu87_4 +# 93| r93_2(int) = Load : &:r93_1, ~m? # 93| r93_3(glval) = VariableAddress[y] : -# 93| r93_4(int) = Load : &:r93_3, ~mu87_4 +# 93| r93_4(int) = Load : &:r93_3, ~m? # 93| r93_5(bool) = CompareGT : r93_2, r93_4 # 93| r93_6(glval) = VariableAddress[b] : # 93| mu93_7(bool) = Store : &:r93_6, r93_5 # 94| r94_1(glval) = VariableAddress[x] : -# 94| r94_2(int) = Load : &:r94_1, ~mu87_4 +# 94| r94_2(int) = Load : &:r94_1, ~m? # 94| r94_3(glval) = VariableAddress[y] : -# 94| r94_4(int) = Load : &:r94_3, ~mu87_4 +# 94| r94_4(int) = Load : &:r94_3, ~m? # 94| r94_5(bool) = CompareLE : r94_2, r94_4 # 94| r94_6(glval) = VariableAddress[b] : # 94| mu94_7(bool) = Store : &:r94_6, r94_5 # 95| r95_1(glval) = VariableAddress[x] : -# 95| r95_2(int) = Load : &:r95_1, ~mu87_4 +# 95| r95_2(int) = Load : &:r95_1, ~m? # 95| r95_3(glval) = VariableAddress[y] : -# 95| r95_4(int) = Load : &:r95_3, ~mu87_4 +# 95| r95_4(int) = Load : &:r95_3, ~m? # 95| r95_5(bool) = CompareGE : r95_2, r95_4 # 95| r95_6(glval) = VariableAddress[b] : # 95| mu95_7(bool) = Store : &:r95_6, r95_5 # 96| v96_1(void) = NoOp : -# 87| v87_9(void) = ReturnVoid : -# 87| v87_10(void) = UnmodeledUse : mu* -# 87| v87_11(void) = AliasedUse : ~mu87_4 -# 87| v87_12(void) = ExitFunction : +# 87| v87_8(void) = ReturnVoid : +# 87| v87_9(void) = AliasedUse : ~m? +# 87| v87_10(void) = ExitFunction : # 98| void IntegerCrement(int) # 98| Block 0 # 98| v98_1(void) = EnterFunction : # 98| mu98_2(unknown) = AliasedDefinition : # 98| mu98_3(unknown) = InitializeNonLocal : -# 98| mu98_4(unknown) = UnmodeledDefinition : -# 98| r98_5(glval) = VariableAddress[x] : -# 98| mu98_6(int) = InitializeParameter[x] : &:r98_5 +# 98| r98_4(glval) = VariableAddress[x] : +# 98| mu98_5(int) = InitializeParameter[x] : &:r98_4 # 99| r99_1(glval) = VariableAddress[y] : # 99| mu99_2(int) = Uninitialized[y] : &:r99_1 # 101| r101_1(glval) = VariableAddress[x] : -# 101| r101_2(int) = Load : &:r101_1, ~mu98_4 +# 101| r101_2(int) = Load : &:r101_1, ~m? # 101| r101_3(int) = Constant[1] : # 101| r101_4(int) = Add : r101_2, r101_3 # 101| mu101_5(int) = Store : &:r101_1, r101_4 # 101| r101_6(glval) = VariableAddress[y] : # 101| mu101_7(int) = Store : &:r101_6, r101_4 # 102| r102_1(glval) = VariableAddress[x] : -# 102| r102_2(int) = Load : &:r102_1, ~mu98_4 +# 102| r102_2(int) = Load : &:r102_1, ~m? # 102| r102_3(int) = Constant[1] : # 102| r102_4(int) = Sub : r102_2, r102_3 # 102| mu102_5(int) = Store : &:r102_1, r102_4 # 102| r102_6(glval) = VariableAddress[y] : # 102| mu102_7(int) = Store : &:r102_6, r102_4 # 103| r103_1(glval) = VariableAddress[x] : -# 103| r103_2(int) = Load : &:r103_1, ~mu98_4 +# 103| r103_2(int) = Load : &:r103_1, ~m? # 103| r103_3(int) = Constant[1] : # 103| r103_4(int) = Add : r103_2, r103_3 # 103| mu103_5(int) = Store : &:r103_1, r103_4 @@ -1098,7 +1080,7 @@ ir.cpp: # 103| r103_7(glval) = VariableAddress[y] : # 103| mu103_8(int) = Store : &:r103_7, r103_6 # 104| r104_1(glval) = VariableAddress[x] : -# 104| r104_2(int) = Load : &:r104_1, ~mu98_4 +# 104| r104_2(int) = Load : &:r104_1, ~m? # 104| r104_3(int) = Constant[1] : # 104| r104_4(int) = Sub : r104_2, r104_3 # 104| mu104_5(int) = Store : &:r104_1, r104_4 @@ -1106,23 +1088,21 @@ ir.cpp: # 104| r104_7(glval) = VariableAddress[y] : # 104| mu104_8(int) = Store : &:r104_7, r104_6 # 105| v105_1(void) = NoOp : -# 98| v98_7(void) = ReturnVoid : -# 98| v98_8(void) = UnmodeledUse : mu* -# 98| v98_9(void) = AliasedUse : ~mu98_4 -# 98| v98_10(void) = ExitFunction : +# 98| v98_6(void) = ReturnVoid : +# 98| v98_7(void) = AliasedUse : ~m? +# 98| v98_8(void) = ExitFunction : # 107| void IntegerCrement_LValue(int) # 107| Block 0 # 107| v107_1(void) = EnterFunction : # 107| mu107_2(unknown) = AliasedDefinition : # 107| mu107_3(unknown) = InitializeNonLocal : -# 107| mu107_4(unknown) = UnmodeledDefinition : -# 107| r107_5(glval) = VariableAddress[x] : -# 107| mu107_6(int) = InitializeParameter[x] : &:r107_5 +# 107| r107_4(glval) = VariableAddress[x] : +# 107| mu107_5(int) = InitializeParameter[x] : &:r107_4 # 108| r108_1(glval) = VariableAddress[p] : # 108| mu108_2(int *) = Uninitialized[p] : &:r108_1 # 110| r110_1(glval) = VariableAddress[x] : -# 110| r110_2(int) = Load : &:r110_1, ~mu107_4 +# 110| r110_2(int) = Load : &:r110_1, ~m? # 110| r110_3(int) = Constant[1] : # 110| r110_4(int) = Add : r110_2, r110_3 # 110| mu110_5(int) = Store : &:r110_1, r110_4 @@ -1131,7 +1111,7 @@ ir.cpp: # 110| r110_8(glval) = VariableAddress[p] : # 110| mu110_9(int *) = Store : &:r110_8, r110_7 # 111| r111_1(glval) = VariableAddress[x] : -# 111| r111_2(int) = Load : &:r111_1, ~mu107_4 +# 111| r111_2(int) = Load : &:r111_1, ~m? # 111| r111_3(int) = Constant[1] : # 111| r111_4(int) = Sub : r111_2, r111_3 # 111| mu111_5(int) = Store : &:r111_1, r111_4 @@ -1140,181 +1120,175 @@ ir.cpp: # 111| r111_8(glval) = VariableAddress[p] : # 111| mu111_9(int *) = Store : &:r111_8, r111_7 # 112| v112_1(void) = NoOp : -# 107| v107_7(void) = ReturnVoid : -# 107| v107_8(void) = UnmodeledUse : mu* -# 107| v107_9(void) = AliasedUse : ~mu107_4 -# 107| v107_10(void) = ExitFunction : +# 107| v107_6(void) = ReturnVoid : +# 107| v107_7(void) = AliasedUse : ~m? +# 107| v107_8(void) = ExitFunction : # 114| void FloatOps(double, double) # 114| Block 0 # 114| v114_1(void) = EnterFunction : # 114| mu114_2(unknown) = AliasedDefinition : # 114| mu114_3(unknown) = InitializeNonLocal : -# 114| mu114_4(unknown) = UnmodeledDefinition : -# 114| r114_5(glval) = VariableAddress[x] : -# 114| mu114_6(double) = InitializeParameter[x] : &:r114_5 -# 114| r114_7(glval) = VariableAddress[y] : -# 114| mu114_8(double) = InitializeParameter[y] : &:r114_7 +# 114| r114_4(glval) = VariableAddress[x] : +# 114| mu114_5(double) = InitializeParameter[x] : &:r114_4 +# 114| r114_6(glval) = VariableAddress[y] : +# 114| mu114_7(double) = InitializeParameter[y] : &:r114_6 # 115| r115_1(glval) = VariableAddress[z] : # 115| mu115_2(double) = Uninitialized[z] : &:r115_1 # 117| r117_1(glval) = VariableAddress[x] : -# 117| r117_2(double) = Load : &:r117_1, ~mu114_4 +# 117| r117_2(double) = Load : &:r117_1, ~m? # 117| r117_3(glval) = VariableAddress[y] : -# 117| r117_4(double) = Load : &:r117_3, ~mu114_4 +# 117| r117_4(double) = Load : &:r117_3, ~m? # 117| r117_5(double) = Add : r117_2, r117_4 # 117| r117_6(glval) = VariableAddress[z] : # 117| mu117_7(double) = Store : &:r117_6, r117_5 # 118| r118_1(glval) = VariableAddress[x] : -# 118| r118_2(double) = Load : &:r118_1, ~mu114_4 +# 118| r118_2(double) = Load : &:r118_1, ~m? # 118| r118_3(glval) = VariableAddress[y] : -# 118| r118_4(double) = Load : &:r118_3, ~mu114_4 +# 118| r118_4(double) = Load : &:r118_3, ~m? # 118| r118_5(double) = Sub : r118_2, r118_4 # 118| r118_6(glval) = VariableAddress[z] : # 118| mu118_7(double) = Store : &:r118_6, r118_5 # 119| r119_1(glval) = VariableAddress[x] : -# 119| r119_2(double) = Load : &:r119_1, ~mu114_4 +# 119| r119_2(double) = Load : &:r119_1, ~m? # 119| r119_3(glval) = VariableAddress[y] : -# 119| r119_4(double) = Load : &:r119_3, ~mu114_4 +# 119| r119_4(double) = Load : &:r119_3, ~m? # 119| r119_5(double) = Mul : r119_2, r119_4 # 119| r119_6(glval) = VariableAddress[z] : # 119| mu119_7(double) = Store : &:r119_6, r119_5 # 120| r120_1(glval) = VariableAddress[x] : -# 120| r120_2(double) = Load : &:r120_1, ~mu114_4 +# 120| r120_2(double) = Load : &:r120_1, ~m? # 120| r120_3(glval) = VariableAddress[y] : -# 120| r120_4(double) = Load : &:r120_3, ~mu114_4 +# 120| r120_4(double) = Load : &:r120_3, ~m? # 120| r120_5(double) = Div : r120_2, r120_4 # 120| r120_6(glval) = VariableAddress[z] : # 120| mu120_7(double) = Store : &:r120_6, r120_5 # 122| r122_1(glval) = VariableAddress[x] : -# 122| r122_2(double) = Load : &:r122_1, ~mu114_4 +# 122| r122_2(double) = Load : &:r122_1, ~m? # 122| r122_3(glval) = VariableAddress[z] : # 122| mu122_4(double) = Store : &:r122_3, r122_2 # 124| r124_1(glval) = VariableAddress[x] : -# 124| r124_2(double) = Load : &:r124_1, ~mu114_4 +# 124| r124_2(double) = Load : &:r124_1, ~m? # 124| r124_3(glval) = VariableAddress[z] : -# 124| r124_4(double) = Load : &:r124_3, ~mu114_4 +# 124| r124_4(double) = Load : &:r124_3, ~m? # 124| r124_5(double) = Add : r124_4, r124_2 # 124| mu124_6(double) = Store : &:r124_3, r124_5 # 125| r125_1(glval) = VariableAddress[x] : -# 125| r125_2(double) = Load : &:r125_1, ~mu114_4 +# 125| r125_2(double) = Load : &:r125_1, ~m? # 125| r125_3(glval) = VariableAddress[z] : -# 125| r125_4(double) = Load : &:r125_3, ~mu114_4 +# 125| r125_4(double) = Load : &:r125_3, ~m? # 125| r125_5(double) = Sub : r125_4, r125_2 # 125| mu125_6(double) = Store : &:r125_3, r125_5 # 126| r126_1(glval) = VariableAddress[x] : -# 126| r126_2(double) = Load : &:r126_1, ~mu114_4 +# 126| r126_2(double) = Load : &:r126_1, ~m? # 126| r126_3(glval) = VariableAddress[z] : -# 126| r126_4(double) = Load : &:r126_3, ~mu114_4 +# 126| r126_4(double) = Load : &:r126_3, ~m? # 126| r126_5(double) = Mul : r126_4, r126_2 # 126| mu126_6(double) = Store : &:r126_3, r126_5 # 127| r127_1(glval) = VariableAddress[x] : -# 127| r127_2(double) = Load : &:r127_1, ~mu114_4 +# 127| r127_2(double) = Load : &:r127_1, ~m? # 127| r127_3(glval) = VariableAddress[z] : -# 127| r127_4(double) = Load : &:r127_3, ~mu114_4 +# 127| r127_4(double) = Load : &:r127_3, ~m? # 127| r127_5(double) = Div : r127_4, r127_2 # 127| mu127_6(double) = Store : &:r127_3, r127_5 # 129| r129_1(glval) = VariableAddress[x] : -# 129| r129_2(double) = Load : &:r129_1, ~mu114_4 +# 129| r129_2(double) = Load : &:r129_1, ~m? # 129| r129_3(double) = CopyValue : r129_2 # 129| r129_4(glval) = VariableAddress[z] : # 129| mu129_5(double) = Store : &:r129_4, r129_3 # 130| r130_1(glval) = VariableAddress[x] : -# 130| r130_2(double) = Load : &:r130_1, ~mu114_4 +# 130| r130_2(double) = Load : &:r130_1, ~m? # 130| r130_3(double) = Negate : r130_2 # 130| r130_4(glval) = VariableAddress[z] : # 130| mu130_5(double) = Store : &:r130_4, r130_3 # 131| v131_1(void) = NoOp : -# 114| v114_9(void) = ReturnVoid : -# 114| v114_10(void) = UnmodeledUse : mu* -# 114| v114_11(void) = AliasedUse : ~mu114_4 -# 114| v114_12(void) = ExitFunction : +# 114| v114_8(void) = ReturnVoid : +# 114| v114_9(void) = AliasedUse : ~m? +# 114| v114_10(void) = ExitFunction : # 133| void FloatCompare(double, double) # 133| Block 0 # 133| v133_1(void) = EnterFunction : # 133| mu133_2(unknown) = AliasedDefinition : # 133| mu133_3(unknown) = InitializeNonLocal : -# 133| mu133_4(unknown) = UnmodeledDefinition : -# 133| r133_5(glval) = VariableAddress[x] : -# 133| mu133_6(double) = InitializeParameter[x] : &:r133_5 -# 133| r133_7(glval) = VariableAddress[y] : -# 133| mu133_8(double) = InitializeParameter[y] : &:r133_7 +# 133| r133_4(glval) = VariableAddress[x] : +# 133| mu133_5(double) = InitializeParameter[x] : &:r133_4 +# 133| r133_6(glval) = VariableAddress[y] : +# 133| mu133_7(double) = InitializeParameter[y] : &:r133_6 # 134| r134_1(glval) = VariableAddress[b] : # 134| mu134_2(bool) = Uninitialized[b] : &:r134_1 # 136| r136_1(glval) = VariableAddress[x] : -# 136| r136_2(double) = Load : &:r136_1, ~mu133_4 +# 136| r136_2(double) = Load : &:r136_1, ~m? # 136| r136_3(glval) = VariableAddress[y] : -# 136| r136_4(double) = Load : &:r136_3, ~mu133_4 +# 136| r136_4(double) = Load : &:r136_3, ~m? # 136| r136_5(bool) = CompareEQ : r136_2, r136_4 # 136| r136_6(glval) = VariableAddress[b] : # 136| mu136_7(bool) = Store : &:r136_6, r136_5 # 137| r137_1(glval) = VariableAddress[x] : -# 137| r137_2(double) = Load : &:r137_1, ~mu133_4 +# 137| r137_2(double) = Load : &:r137_1, ~m? # 137| r137_3(glval) = VariableAddress[y] : -# 137| r137_4(double) = Load : &:r137_3, ~mu133_4 +# 137| r137_4(double) = Load : &:r137_3, ~m? # 137| r137_5(bool) = CompareNE : r137_2, r137_4 # 137| r137_6(glval) = VariableAddress[b] : # 137| mu137_7(bool) = Store : &:r137_6, r137_5 # 138| r138_1(glval) = VariableAddress[x] : -# 138| r138_2(double) = Load : &:r138_1, ~mu133_4 +# 138| r138_2(double) = Load : &:r138_1, ~m? # 138| r138_3(glval) = VariableAddress[y] : -# 138| r138_4(double) = Load : &:r138_3, ~mu133_4 +# 138| r138_4(double) = Load : &:r138_3, ~m? # 138| r138_5(bool) = CompareLT : r138_2, r138_4 # 138| r138_6(glval) = VariableAddress[b] : # 138| mu138_7(bool) = Store : &:r138_6, r138_5 # 139| r139_1(glval) = VariableAddress[x] : -# 139| r139_2(double) = Load : &:r139_1, ~mu133_4 +# 139| r139_2(double) = Load : &:r139_1, ~m? # 139| r139_3(glval) = VariableAddress[y] : -# 139| r139_4(double) = Load : &:r139_3, ~mu133_4 +# 139| r139_4(double) = Load : &:r139_3, ~m? # 139| r139_5(bool) = CompareGT : r139_2, r139_4 # 139| r139_6(glval) = VariableAddress[b] : # 139| mu139_7(bool) = Store : &:r139_6, r139_5 # 140| r140_1(glval) = VariableAddress[x] : -# 140| r140_2(double) = Load : &:r140_1, ~mu133_4 +# 140| r140_2(double) = Load : &:r140_1, ~m? # 140| r140_3(glval) = VariableAddress[y] : -# 140| r140_4(double) = Load : &:r140_3, ~mu133_4 +# 140| r140_4(double) = Load : &:r140_3, ~m? # 140| r140_5(bool) = CompareLE : r140_2, r140_4 # 140| r140_6(glval) = VariableAddress[b] : # 140| mu140_7(bool) = Store : &:r140_6, r140_5 # 141| r141_1(glval) = VariableAddress[x] : -# 141| r141_2(double) = Load : &:r141_1, ~mu133_4 +# 141| r141_2(double) = Load : &:r141_1, ~m? # 141| r141_3(glval) = VariableAddress[y] : -# 141| r141_4(double) = Load : &:r141_3, ~mu133_4 +# 141| r141_4(double) = Load : &:r141_3, ~m? # 141| r141_5(bool) = CompareGE : r141_2, r141_4 # 141| r141_6(glval) = VariableAddress[b] : # 141| mu141_7(bool) = Store : &:r141_6, r141_5 # 142| v142_1(void) = NoOp : -# 133| v133_9(void) = ReturnVoid : -# 133| v133_10(void) = UnmodeledUse : mu* -# 133| v133_11(void) = AliasedUse : ~mu133_4 -# 133| v133_12(void) = ExitFunction : +# 133| v133_8(void) = ReturnVoid : +# 133| v133_9(void) = AliasedUse : ~m? +# 133| v133_10(void) = ExitFunction : # 144| void FloatCrement(float) # 144| Block 0 # 144| v144_1(void) = EnterFunction : # 144| mu144_2(unknown) = AliasedDefinition : # 144| mu144_3(unknown) = InitializeNonLocal : -# 144| mu144_4(unknown) = UnmodeledDefinition : -# 144| r144_5(glval) = VariableAddress[x] : -# 144| mu144_6(float) = InitializeParameter[x] : &:r144_5 +# 144| r144_4(glval) = VariableAddress[x] : +# 144| mu144_5(float) = InitializeParameter[x] : &:r144_4 # 145| r145_1(glval) = VariableAddress[y] : # 145| mu145_2(float) = Uninitialized[y] : &:r145_1 # 147| r147_1(glval) = VariableAddress[x] : -# 147| r147_2(float) = Load : &:r147_1, ~mu144_4 +# 147| r147_2(float) = Load : &:r147_1, ~m? # 147| r147_3(float) = Constant[1.0] : # 147| r147_4(float) = Add : r147_2, r147_3 # 147| mu147_5(float) = Store : &:r147_1, r147_4 # 147| r147_6(glval) = VariableAddress[y] : # 147| mu147_7(float) = Store : &:r147_6, r147_4 # 148| r148_1(glval) = VariableAddress[x] : -# 148| r148_2(float) = Load : &:r148_1, ~mu144_4 +# 148| r148_2(float) = Load : &:r148_1, ~m? # 148| r148_3(float) = Constant[1.0] : # 148| r148_4(float) = Sub : r148_2, r148_3 # 148| mu148_5(float) = Store : &:r148_1, r148_4 # 148| r148_6(glval) = VariableAddress[y] : # 148| mu148_7(float) = Store : &:r148_6, r148_4 # 149| r149_1(glval) = VariableAddress[x] : -# 149| r149_2(float) = Load : &:r149_1, ~mu144_4 +# 149| r149_2(float) = Load : &:r149_1, ~m? # 149| r149_3(float) = Constant[1.0] : # 149| r149_4(float) = Add : r149_2, r149_3 # 149| mu149_5(float) = Store : &:r149_1, r149_4 @@ -1322,7 +1296,7 @@ ir.cpp: # 149| r149_7(glval) = VariableAddress[y] : # 149| mu149_8(float) = Store : &:r149_7, r149_6 # 150| r150_1(glval) = VariableAddress[x] : -# 150| r150_2(float) = Load : &:r150_1, ~mu144_4 +# 150| r150_2(float) = Load : &:r150_1, ~m? # 150| r150_3(float) = Constant[1.0] : # 150| r150_4(float) = Sub : r150_2, r150_3 # 150| mu150_5(float) = Store : &:r150_1, r150_4 @@ -1330,136 +1304,132 @@ ir.cpp: # 150| r150_7(glval) = VariableAddress[y] : # 150| mu150_8(float) = Store : &:r150_7, r150_6 # 151| v151_1(void) = NoOp : -# 144| v144_7(void) = ReturnVoid : -# 144| v144_8(void) = UnmodeledUse : mu* -# 144| v144_9(void) = AliasedUse : ~mu144_4 -# 144| v144_10(void) = ExitFunction : +# 144| v144_6(void) = ReturnVoid : +# 144| v144_7(void) = AliasedUse : ~m? +# 144| v144_8(void) = ExitFunction : # 153| void PointerOps(int*, int) # 153| Block 0 # 153| v153_1(void) = EnterFunction : # 153| mu153_2(unknown) = AliasedDefinition : # 153| mu153_3(unknown) = InitializeNonLocal : -# 153| mu153_4(unknown) = UnmodeledDefinition : -# 153| r153_5(glval) = VariableAddress[p] : -# 153| mu153_6(int *) = InitializeParameter[p] : &:r153_5 -# 153| r153_7(int *) = Load : &:r153_5, ~mu153_4 -# 153| mu153_8(unknown) = InitializeIndirection[p] : &:r153_7 -# 153| r153_9(glval) = VariableAddress[i] : -# 153| mu153_10(int) = InitializeParameter[i] : &:r153_9 +# 153| r153_4(glval) = VariableAddress[p] : +# 153| mu153_5(int *) = InitializeParameter[p] : &:r153_4 +# 153| r153_6(int *) = Load : &:r153_4, ~m? +# 153| mu153_7(unknown) = InitializeIndirection[p] : &:r153_6 +# 153| r153_8(glval) = VariableAddress[i] : +# 153| mu153_9(int) = InitializeParameter[i] : &:r153_8 # 154| r154_1(glval) = VariableAddress[q] : # 154| mu154_2(int *) = Uninitialized[q] : &:r154_1 # 155| r155_1(glval) = VariableAddress[b] : # 155| mu155_2(bool) = Uninitialized[b] : &:r155_1 # 157| r157_1(glval) = VariableAddress[p] : -# 157| r157_2(int *) = Load : &:r157_1, ~mu153_4 +# 157| r157_2(int *) = Load : &:r157_1, ~m? # 157| r157_3(glval) = VariableAddress[i] : -# 157| r157_4(int) = Load : &:r157_3, ~mu153_4 +# 157| r157_4(int) = Load : &:r157_3, ~m? # 157| r157_5(int *) = PointerAdd[4] : r157_2, r157_4 # 157| r157_6(glval) = VariableAddress[q] : # 157| mu157_7(int *) = Store : &:r157_6, r157_5 # 158| r158_1(glval) = VariableAddress[i] : -# 158| r158_2(int) = Load : &:r158_1, ~mu153_4 +# 158| r158_2(int) = Load : &:r158_1, ~m? # 158| r158_3(glval) = VariableAddress[p] : -# 158| r158_4(int *) = Load : &:r158_3, ~mu153_4 +# 158| r158_4(int *) = Load : &:r158_3, ~m? # 158| r158_5(int *) = PointerAdd[4] : r158_4, r158_2 # 158| r158_6(glval) = VariableAddress[q] : # 158| mu158_7(int *) = Store : &:r158_6, r158_5 # 159| r159_1(glval) = VariableAddress[p] : -# 159| r159_2(int *) = Load : &:r159_1, ~mu153_4 +# 159| r159_2(int *) = Load : &:r159_1, ~m? # 159| r159_3(glval) = VariableAddress[i] : -# 159| r159_4(int) = Load : &:r159_3, ~mu153_4 +# 159| r159_4(int) = Load : &:r159_3, ~m? # 159| r159_5(int *) = PointerSub[4] : r159_2, r159_4 # 159| r159_6(glval) = VariableAddress[q] : # 159| mu159_7(int *) = Store : &:r159_6, r159_5 # 160| r160_1(glval) = VariableAddress[p] : -# 160| r160_2(int *) = Load : &:r160_1, ~mu153_4 +# 160| r160_2(int *) = Load : &:r160_1, ~m? # 160| r160_3(glval) = VariableAddress[q] : -# 160| r160_4(int *) = Load : &:r160_3, ~mu153_4 +# 160| r160_4(int *) = Load : &:r160_3, ~m? # 160| r160_5(long) = PointerDiff[4] : r160_2, r160_4 # 160| r160_6(int) = Convert : r160_5 # 160| r160_7(glval) = VariableAddress[i] : # 160| mu160_8(int) = Store : &:r160_7, r160_6 # 162| r162_1(glval) = VariableAddress[p] : -# 162| r162_2(int *) = Load : &:r162_1, ~mu153_4 +# 162| r162_2(int *) = Load : &:r162_1, ~m? # 162| r162_3(glval) = VariableAddress[q] : # 162| mu162_4(int *) = Store : &:r162_3, r162_2 # 164| r164_1(glval) = VariableAddress[i] : -# 164| r164_2(int) = Load : &:r164_1, ~mu153_4 +# 164| r164_2(int) = Load : &:r164_1, ~m? # 164| r164_3(glval) = VariableAddress[q] : -# 164| r164_4(int *) = Load : &:r164_3, ~mu153_4 +# 164| r164_4(int *) = Load : &:r164_3, ~m? # 164| r164_5(int *) = PointerAdd[4] : r164_4, r164_2 # 164| mu164_6(int *) = Store : &:r164_3, r164_5 # 165| r165_1(glval) = VariableAddress[i] : -# 165| r165_2(int) = Load : &:r165_1, ~mu153_4 +# 165| r165_2(int) = Load : &:r165_1, ~m? # 165| r165_3(glval) = VariableAddress[q] : -# 165| r165_4(int *) = Load : &:r165_3, ~mu153_4 +# 165| r165_4(int *) = Load : &:r165_3, ~m? # 165| r165_5(int *) = PointerSub[4] : r165_4, r165_2 # 165| mu165_6(int *) = Store : &:r165_3, r165_5 # 167| r167_1(glval) = VariableAddress[p] : -# 167| r167_2(int *) = Load : &:r167_1, ~mu153_4 +# 167| r167_2(int *) = Load : &:r167_1, ~m? # 167| r167_3(int *) = Constant[0] : # 167| r167_4(bool) = CompareNE : r167_2, r167_3 # 167| r167_5(glval) = VariableAddress[b] : # 167| mu167_6(bool) = Store : &:r167_5, r167_4 # 168| r168_1(glval) = VariableAddress[p] : -# 168| r168_2(int *) = Load : &:r168_1, ~mu153_4 +# 168| r168_2(int *) = Load : &:r168_1, ~m? # 168| r168_3(int *) = Constant[0] : # 168| r168_4(bool) = CompareNE : r168_2, r168_3 # 168| r168_5(bool) = LogicalNot : r168_4 # 168| r168_6(glval) = VariableAddress[b] : # 168| mu168_7(bool) = Store : &:r168_6, r168_5 # 169| v169_1(void) = NoOp : -# 153| v153_11(void) = ReturnIndirection[p] : &:r153_7, ~mu153_4 -# 153| v153_12(void) = ReturnVoid : -# 153| v153_13(void) = UnmodeledUse : mu* -# 153| v153_14(void) = AliasedUse : ~mu153_4 -# 153| v153_15(void) = ExitFunction : +# 153| v153_10(void) = ReturnIndirection[p] : &:r153_6, ~m? +# 153| v153_11(void) = ReturnVoid : +# 153| v153_12(void) = AliasedUse : ~m? +# 153| v153_13(void) = ExitFunction : # 171| void ArrayAccess(int*, int) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[p] : -# 171| mu171_6(int *) = InitializeParameter[p] : &:r171_5 -# 171| r171_7(int *) = Load : &:r171_5, ~mu171_4 -# 171| mu171_8(unknown) = InitializeIndirection[p] : &:r171_7 -# 171| r171_9(glval) = VariableAddress[i] : -# 171| mu171_10(int) = InitializeParameter[i] : &:r171_9 +# 171| r171_4(glval) = VariableAddress[p] : +# 171| mu171_5(int *) = InitializeParameter[p] : &:r171_4 +# 171| r171_6(int *) = Load : &:r171_4, ~m? +# 171| mu171_7(unknown) = InitializeIndirection[p] : &:r171_6 +# 171| r171_8(glval) = VariableAddress[i] : +# 171| mu171_9(int) = InitializeParameter[i] : &:r171_8 # 172| r172_1(glval) = VariableAddress[x] : # 172| mu172_2(int) = Uninitialized[x] : &:r172_1 # 174| r174_1(glval) = VariableAddress[p] : -# 174| r174_2(int *) = Load : &:r174_1, ~mu171_4 +# 174| r174_2(int *) = Load : &:r174_1, ~m? # 174| r174_3(glval) = VariableAddress[i] : -# 174| r174_4(int) = Load : &:r174_3, ~mu171_4 +# 174| r174_4(int) = Load : &:r174_3, ~m? # 174| r174_5(glval) = PointerAdd[4] : r174_2, r174_4 -# 174| r174_6(int) = Load : &:r174_5, ~mu171_4 +# 174| r174_6(int) = Load : &:r174_5, ~m? # 174| r174_7(glval) = VariableAddress[x] : # 174| mu174_8(int) = Store : &:r174_7, r174_6 # 175| r175_1(glval) = VariableAddress[p] : -# 175| r175_2(int *) = Load : &:r175_1, ~mu171_4 +# 175| r175_2(int *) = Load : &:r175_1, ~m? # 175| r175_3(glval) = VariableAddress[i] : -# 175| r175_4(int) = Load : &:r175_3, ~mu171_4 +# 175| r175_4(int) = Load : &:r175_3, ~m? # 175| r175_5(glval) = PointerAdd[4] : r175_2, r175_4 -# 175| r175_6(int) = Load : &:r175_5, ~mu171_4 +# 175| r175_6(int) = Load : &:r175_5, ~m? # 175| r175_7(glval) = VariableAddress[x] : # 175| mu175_8(int) = Store : &:r175_7, r175_6 # 177| r177_1(glval) = VariableAddress[x] : -# 177| r177_2(int) = Load : &:r177_1, ~mu171_4 +# 177| r177_2(int) = Load : &:r177_1, ~m? # 177| r177_3(glval) = VariableAddress[p] : -# 177| r177_4(int *) = Load : &:r177_3, ~mu171_4 +# 177| r177_4(int *) = Load : &:r177_3, ~m? # 177| r177_5(glval) = VariableAddress[i] : -# 177| r177_6(int) = Load : &:r177_5, ~mu171_4 +# 177| r177_6(int) = Load : &:r177_5, ~m? # 177| r177_7(glval) = PointerAdd[4] : r177_4, r177_6 # 177| mu177_8(int) = Store : &:r177_7, r177_2 # 178| r178_1(glval) = VariableAddress[x] : -# 178| r178_2(int) = Load : &:r178_1, ~mu171_4 +# 178| r178_2(int) = Load : &:r178_1, ~m? # 178| r178_3(glval) = VariableAddress[p] : -# 178| r178_4(int *) = Load : &:r178_3, ~mu171_4 +# 178| r178_4(int *) = Load : &:r178_3, ~m? # 178| r178_5(glval) = VariableAddress[i] : -# 178| r178_6(int) = Load : &:r178_5, ~mu171_4 +# 178| r178_6(int) = Load : &:r178_5, ~m? # 178| r178_7(glval) = PointerAdd[4] : r178_4, r178_6 # 178| mu178_8(int) = Store : &:r178_7, r178_2 # 180| r180_1(glval) = VariableAddress[a] : @@ -1467,57 +1437,55 @@ ir.cpp: # 181| r181_1(glval) = VariableAddress[a] : # 181| r181_2(int *) = Convert : r181_1 # 181| r181_3(glval) = VariableAddress[i] : -# 181| r181_4(int) = Load : &:r181_3, ~mu171_4 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| r181_5(glval) = PointerAdd[4] : r181_2, r181_4 -# 181| r181_6(int) = Load : &:r181_5, ~mu171_4 +# 181| r181_6(int) = Load : &:r181_5, ~m? # 181| r181_7(glval) = VariableAddress[x] : # 181| mu181_8(int) = Store : &:r181_7, r181_6 # 182| r182_1(glval) = VariableAddress[a] : # 182| r182_2(int *) = Convert : r182_1 # 182| r182_3(glval) = VariableAddress[i] : -# 182| r182_4(int) = Load : &:r182_3, ~mu171_4 +# 182| r182_4(int) = Load : &:r182_3, ~m? # 182| r182_5(glval) = PointerAdd[4] : r182_2, r182_4 -# 182| r182_6(int) = Load : &:r182_5, ~mu171_4 +# 182| r182_6(int) = Load : &:r182_5, ~m? # 182| r182_7(glval) = VariableAddress[x] : # 182| mu182_8(int) = Store : &:r182_7, r182_6 # 183| r183_1(glval) = VariableAddress[x] : -# 183| r183_2(int) = Load : &:r183_1, ~mu171_4 +# 183| r183_2(int) = Load : &:r183_1, ~m? # 183| r183_3(glval) = VariableAddress[a] : # 183| r183_4(int *) = Convert : r183_3 # 183| r183_5(glval) = VariableAddress[i] : -# 183| r183_6(int) = Load : &:r183_5, ~mu171_4 +# 183| r183_6(int) = Load : &:r183_5, ~m? # 183| r183_7(glval) = PointerAdd[4] : r183_4, r183_6 # 183| mu183_8(int) = Store : &:r183_7, r183_2 # 184| r184_1(glval) = VariableAddress[x] : -# 184| r184_2(int) = Load : &:r184_1, ~mu171_4 +# 184| r184_2(int) = Load : &:r184_1, ~m? # 184| r184_3(glval) = VariableAddress[a] : # 184| r184_4(int *) = Convert : r184_3 # 184| r184_5(glval) = VariableAddress[i] : -# 184| r184_6(int) = Load : &:r184_5, ~mu171_4 +# 184| r184_6(int) = Load : &:r184_5, ~m? # 184| r184_7(glval) = PointerAdd[4] : r184_4, r184_6 # 184| mu184_8(int) = Store : &:r184_7, r184_2 # 185| v185_1(void) = NoOp : -# 171| v171_11(void) = ReturnIndirection[p] : &:r171_7, ~mu171_4 -# 171| v171_12(void) = ReturnVoid : -# 171| v171_13(void) = UnmodeledUse : mu* -# 171| v171_14(void) = AliasedUse : ~mu171_4 -# 171| v171_15(void) = ExitFunction : +# 171| v171_10(void) = ReturnIndirection[p] : &:r171_6, ~m? +# 171| v171_11(void) = ReturnVoid : +# 171| v171_12(void) = AliasedUse : ~m? +# 171| v171_13(void) = ExitFunction : # 187| void StringLiteral(int) # 187| Block 0 # 187| v187_1(void) = EnterFunction : # 187| mu187_2(unknown) = AliasedDefinition : # 187| mu187_3(unknown) = InitializeNonLocal : -# 187| mu187_4(unknown) = UnmodeledDefinition : -# 187| r187_5(glval) = VariableAddress[i] : -# 187| mu187_6(int) = InitializeParameter[i] : &:r187_5 +# 187| r187_4(glval) = VariableAddress[i] : +# 187| mu187_5(int) = InitializeParameter[i] : &:r187_4 # 188| r188_1(glval) = VariableAddress[c] : # 188| r188_2(glval) = StringConstant["Foo"] : # 188| r188_3(char *) = Convert : r188_2 # 188| r188_4(glval) = VariableAddress[i] : -# 188| r188_5(int) = Load : &:r188_4, ~mu187_4 +# 188| r188_5(int) = Load : &:r188_4, ~m? # 188| r188_6(glval) = PointerAdd[1] : r188_3, r188_5 -# 188| r188_7(char) = Load : &:r188_6, ~mu187_4 +# 188| r188_7(char) = Load : &:r188_6, ~m? # 188| mu188_8(char) = Store : &:r188_1, r188_7 # 189| r189_1(glval) = VariableAddress[pwc] : # 189| r189_2(glval) = StringConstant[L"Bar"] : @@ -1526,112 +1494,108 @@ ir.cpp: # 189| mu189_5(wchar_t *) = Store : &:r189_1, r189_4 # 190| r190_1(glval) = VariableAddress[wc] : # 190| r190_2(glval) = VariableAddress[pwc] : -# 190| r190_3(wchar_t *) = Load : &:r190_2, ~mu187_4 +# 190| r190_3(wchar_t *) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[i] : -# 190| r190_5(int) = Load : &:r190_4, ~mu187_4 +# 190| r190_5(int) = Load : &:r190_4, ~m? # 190| r190_6(glval) = PointerAdd[4] : r190_3, r190_5 -# 190| r190_7(wchar_t) = Load : &:r190_6, ~mu187_4 +# 190| r190_7(wchar_t) = Load : &:r190_6, ~m? # 190| mu190_8(wchar_t) = Store : &:r190_1, r190_7 # 191| v191_1(void) = NoOp : -# 187| v187_7(void) = ReturnVoid : -# 187| v187_8(void) = UnmodeledUse : mu* -# 187| v187_9(void) = AliasedUse : ~mu187_4 -# 187| v187_10(void) = ExitFunction : +# 187| v187_6(void) = ReturnVoid : +# 187| v187_7(void) = AliasedUse : ~m? +# 187| v187_8(void) = ExitFunction : # 193| void PointerCompare(int*, int*) # 193| Block 0 # 193| v193_1(void) = EnterFunction : # 193| mu193_2(unknown) = AliasedDefinition : # 193| mu193_3(unknown) = InitializeNonLocal : -# 193| mu193_4(unknown) = UnmodeledDefinition : -# 193| r193_5(glval) = VariableAddress[p] : -# 193| mu193_6(int *) = InitializeParameter[p] : &:r193_5 -# 193| r193_7(int *) = Load : &:r193_5, ~mu193_4 -# 193| mu193_8(unknown) = InitializeIndirection[p] : &:r193_7 -# 193| r193_9(glval) = VariableAddress[q] : -# 193| mu193_10(int *) = InitializeParameter[q] : &:r193_9 -# 193| r193_11(int *) = Load : &:r193_9, ~mu193_4 -# 193| mu193_12(unknown) = InitializeIndirection[q] : &:r193_11 +# 193| r193_4(glval) = VariableAddress[p] : +# 193| mu193_5(int *) = InitializeParameter[p] : &:r193_4 +# 193| r193_6(int *) = Load : &:r193_4, ~m? +# 193| mu193_7(unknown) = InitializeIndirection[p] : &:r193_6 +# 193| r193_8(glval) = VariableAddress[q] : +# 193| mu193_9(int *) = InitializeParameter[q] : &:r193_8 +# 193| r193_10(int *) = Load : &:r193_8, ~m? +# 193| mu193_11(unknown) = InitializeIndirection[q] : &:r193_10 # 194| r194_1(glval) = VariableAddress[b] : # 194| mu194_2(bool) = Uninitialized[b] : &:r194_1 # 196| r196_1(glval) = VariableAddress[p] : -# 196| r196_2(int *) = Load : &:r196_1, ~mu193_4 +# 196| r196_2(int *) = Load : &:r196_1, ~m? # 196| r196_3(glval) = VariableAddress[q] : -# 196| r196_4(int *) = Load : &:r196_3, ~mu193_4 +# 196| r196_4(int *) = Load : &:r196_3, ~m? # 196| r196_5(bool) = CompareEQ : r196_2, r196_4 # 196| r196_6(glval) = VariableAddress[b] : # 196| mu196_7(bool) = Store : &:r196_6, r196_5 # 197| r197_1(glval) = VariableAddress[p] : -# 197| r197_2(int *) = Load : &:r197_1, ~mu193_4 +# 197| r197_2(int *) = Load : &:r197_1, ~m? # 197| r197_3(glval) = VariableAddress[q] : -# 197| r197_4(int *) = Load : &:r197_3, ~mu193_4 +# 197| r197_4(int *) = Load : &:r197_3, ~m? # 197| r197_5(bool) = CompareNE : r197_2, r197_4 # 197| r197_6(glval) = VariableAddress[b] : # 197| mu197_7(bool) = Store : &:r197_6, r197_5 # 198| r198_1(glval) = VariableAddress[p] : -# 198| r198_2(int *) = Load : &:r198_1, ~mu193_4 +# 198| r198_2(int *) = Load : &:r198_1, ~m? # 198| r198_3(glval) = VariableAddress[q] : -# 198| r198_4(int *) = Load : &:r198_3, ~mu193_4 +# 198| r198_4(int *) = Load : &:r198_3, ~m? # 198| r198_5(bool) = CompareLT : r198_2, r198_4 # 198| r198_6(glval) = VariableAddress[b] : # 198| mu198_7(bool) = Store : &:r198_6, r198_5 # 199| r199_1(glval) = VariableAddress[p] : -# 199| r199_2(int *) = Load : &:r199_1, ~mu193_4 +# 199| r199_2(int *) = Load : &:r199_1, ~m? # 199| r199_3(glval) = VariableAddress[q] : -# 199| r199_4(int *) = Load : &:r199_3, ~mu193_4 +# 199| r199_4(int *) = Load : &:r199_3, ~m? # 199| r199_5(bool) = CompareGT : r199_2, r199_4 # 199| r199_6(glval) = VariableAddress[b] : # 199| mu199_7(bool) = Store : &:r199_6, r199_5 # 200| r200_1(glval) = VariableAddress[p] : -# 200| r200_2(int *) = Load : &:r200_1, ~mu193_4 +# 200| r200_2(int *) = Load : &:r200_1, ~m? # 200| r200_3(glval) = VariableAddress[q] : -# 200| r200_4(int *) = Load : &:r200_3, ~mu193_4 +# 200| r200_4(int *) = Load : &:r200_3, ~m? # 200| r200_5(bool) = CompareLE : r200_2, r200_4 # 200| r200_6(glval) = VariableAddress[b] : # 200| mu200_7(bool) = Store : &:r200_6, r200_5 # 201| r201_1(glval) = VariableAddress[p] : -# 201| r201_2(int *) = Load : &:r201_1, ~mu193_4 +# 201| r201_2(int *) = Load : &:r201_1, ~m? # 201| r201_3(glval) = VariableAddress[q] : -# 201| r201_4(int *) = Load : &:r201_3, ~mu193_4 +# 201| r201_4(int *) = Load : &:r201_3, ~m? # 201| r201_5(bool) = CompareGE : r201_2, r201_4 # 201| r201_6(glval) = VariableAddress[b] : # 201| mu201_7(bool) = Store : &:r201_6, r201_5 # 202| v202_1(void) = NoOp : -# 193| v193_13(void) = ReturnIndirection[p] : &:r193_7, ~mu193_4 -# 193| v193_14(void) = ReturnIndirection[q] : &:r193_11, ~mu193_4 -# 193| v193_15(void) = ReturnVoid : -# 193| v193_16(void) = UnmodeledUse : mu* -# 193| v193_17(void) = AliasedUse : ~mu193_4 -# 193| v193_18(void) = ExitFunction : +# 193| v193_12(void) = ReturnIndirection[p] : &:r193_6, ~m? +# 193| v193_13(void) = ReturnIndirection[q] : &:r193_10, ~m? +# 193| v193_14(void) = ReturnVoid : +# 193| v193_15(void) = AliasedUse : ~m? +# 193| v193_16(void) = ExitFunction : # 204| void PointerCrement(int*) # 204| Block 0 # 204| v204_1(void) = EnterFunction : # 204| mu204_2(unknown) = AliasedDefinition : # 204| mu204_3(unknown) = InitializeNonLocal : -# 204| mu204_4(unknown) = UnmodeledDefinition : -# 204| r204_5(glval) = VariableAddress[p] : -# 204| mu204_6(int *) = InitializeParameter[p] : &:r204_5 -# 204| r204_7(int *) = Load : &:r204_5, ~mu204_4 -# 204| mu204_8(unknown) = InitializeIndirection[p] : &:r204_7 +# 204| r204_4(glval) = VariableAddress[p] : +# 204| mu204_5(int *) = InitializeParameter[p] : &:r204_4 +# 204| r204_6(int *) = Load : &:r204_4, ~m? +# 204| mu204_7(unknown) = InitializeIndirection[p] : &:r204_6 # 205| r205_1(glval) = VariableAddress[q] : # 205| mu205_2(int *) = Uninitialized[q] : &:r205_1 # 207| r207_1(glval) = VariableAddress[p] : -# 207| r207_2(int *) = Load : &:r207_1, ~mu204_4 +# 207| r207_2(int *) = Load : &:r207_1, ~m? # 207| r207_3(int) = Constant[1] : # 207| r207_4(int *) = PointerAdd[4] : r207_2, r207_3 # 207| mu207_5(int *) = Store : &:r207_1, r207_4 # 207| r207_6(glval) = VariableAddress[q] : # 207| mu207_7(int *) = Store : &:r207_6, r207_4 # 208| r208_1(glval) = VariableAddress[p] : -# 208| r208_2(int *) = Load : &:r208_1, ~mu204_4 +# 208| r208_2(int *) = Load : &:r208_1, ~m? # 208| r208_3(int) = Constant[1] : # 208| r208_4(int *) = PointerSub[4] : r208_2, r208_3 # 208| mu208_5(int *) = Store : &:r208_1, r208_4 # 208| r208_6(glval) = VariableAddress[q] : # 208| mu208_7(int *) = Store : &:r208_6, r208_4 # 209| r209_1(glval) = VariableAddress[p] : -# 209| r209_2(int *) = Load : &:r209_1, ~mu204_4 +# 209| r209_2(int *) = Load : &:r209_1, ~m? # 209| r209_3(int) = Constant[1] : # 209| r209_4(int *) = PointerAdd[4] : r209_2, r209_3 # 209| mu209_5(int *) = Store : &:r209_1, r209_4 @@ -1639,7 +1603,7 @@ ir.cpp: # 209| r209_7(glval) = VariableAddress[q] : # 209| mu209_8(int *) = Store : &:r209_7, r209_6 # 210| r210_1(glval) = VariableAddress[p] : -# 210| r210_2(int *) = Load : &:r210_1, ~mu204_4 +# 210| r210_2(int *) = Load : &:r210_1, ~m? # 210| r210_3(int) = Constant[1] : # 210| r210_4(int *) = PointerSub[4] : r210_2, r210_3 # 210| mu210_5(int *) = Store : &:r210_1, r210_4 @@ -1647,134 +1611,126 @@ ir.cpp: # 210| r210_7(glval) = VariableAddress[q] : # 210| mu210_8(int *) = Store : &:r210_7, r210_6 # 211| v211_1(void) = NoOp : -# 204| v204_9(void) = ReturnIndirection[p] : &:r204_7, ~mu204_4 -# 204| v204_10(void) = ReturnVoid : -# 204| v204_11(void) = UnmodeledUse : mu* -# 204| v204_12(void) = AliasedUse : ~mu204_4 -# 204| v204_13(void) = ExitFunction : +# 204| v204_8(void) = ReturnIndirection[p] : &:r204_6, ~m? +# 204| v204_9(void) = ReturnVoid : +# 204| v204_10(void) = AliasedUse : ~m? +# 204| v204_11(void) = ExitFunction : # 213| void CompoundAssignment() # 213| Block 0 -# 213| v213_1(void) = EnterFunction : -# 213| mu213_2(unknown) = AliasedDefinition : -# 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : -# 215| r215_1(glval) = VariableAddress[x] : -# 215| r215_2(int) = Constant[5] : -# 215| mu215_3(int) = Store : &:r215_1, r215_2 -# 216| r216_1(int) = Constant[7] : -# 216| r216_2(glval) = VariableAddress[x] : -# 216| r216_3(int) = Load : &:r216_2, ~mu213_4 -# 216| r216_4(int) = Add : r216_3, r216_1 -# 216| mu216_5(int) = Store : &:r216_2, r216_4 -# 219| r219_1(glval) = VariableAddress[y] : -# 219| r219_2(short) = Constant[5] : -# 219| mu219_3(short) = Store : &:r219_1, r219_2 -# 220| r220_1(glval) = VariableAddress[x] : -# 220| r220_2(int) = Load : &:r220_1, ~mu213_4 -# 220| r220_3(glval) = VariableAddress[y] : -# 220| r220_4(short) = Load : &:r220_3, ~mu213_4 -# 220| r220_5(int) = Convert : r220_4 -# 220| r220_6(int) = Add : r220_5, r220_2 -# 220| r220_7(short) = Convert : r220_6 -# 220| mu220_8(short) = Store : &:r220_3, r220_7 -# 223| r223_1(int) = Constant[1] : -# 223| r223_2(glval) = VariableAddress[y] : -# 223| r223_3(short) = Load : &:r223_2, ~mu213_4 -# 223| r223_4(short) = ShiftLeft : r223_3, r223_1 -# 223| mu223_5(short) = Store : &:r223_2, r223_4 -# 226| r226_1(glval) = VariableAddress[z] : -# 226| r226_2(long) = Constant[7] : -# 226| mu226_3(long) = Store : &:r226_1, r226_2 -# 227| r227_1(float) = Constant[2.0] : -# 227| r227_2(glval) = VariableAddress[z] : -# 227| r227_3(long) = Load : &:r227_2, ~mu213_4 -# 227| r227_4(float) = Convert : r227_3 -# 227| r227_5(float) = Add : r227_4, r227_1 -# 227| r227_6(long) = Convert : r227_5 -# 227| mu227_7(long) = Store : &:r227_2, r227_6 -# 228| v228_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_1(void) = EnterFunction : +# 213| mu213_2(unknown) = AliasedDefinition : +# 213| mu213_3(unknown) = InitializeNonLocal : +# 215| r215_1(glval) = VariableAddress[x] : +# 215| r215_2(int) = Constant[5] : +# 215| mu215_3(int) = Store : &:r215_1, r215_2 +# 216| r216_1(int) = Constant[7] : +# 216| r216_2(glval) = VariableAddress[x] : +# 216| r216_3(int) = Load : &:r216_2, ~m? +# 216| r216_4(int) = Add : r216_3, r216_1 +# 216| mu216_5(int) = Store : &:r216_2, r216_4 +# 219| r219_1(glval) = VariableAddress[y] : +# 219| r219_2(short) = Constant[5] : +# 219| mu219_3(short) = Store : &:r219_1, r219_2 +# 220| r220_1(glval) = VariableAddress[x] : +# 220| r220_2(int) = Load : &:r220_1, ~m? +# 220| r220_3(glval) = VariableAddress[y] : +# 220| r220_4(short) = Load : &:r220_3, ~m? +# 220| r220_5(int) = Convert : r220_4 +# 220| r220_6(int) = Add : r220_5, r220_2 +# 220| r220_7(short) = Convert : r220_6 +# 220| mu220_8(short) = Store : &:r220_3, r220_7 +# 223| r223_1(int) = Constant[1] : +# 223| r223_2(glval) = VariableAddress[y] : +# 223| r223_3(short) = Load : &:r223_2, ~m? +# 223| r223_4(short) = ShiftLeft : r223_3, r223_1 +# 223| mu223_5(short) = Store : &:r223_2, r223_4 +# 226| r226_1(glval) = VariableAddress[z] : +# 226| r226_2(long) = Constant[7] : +# 226| mu226_3(long) = Store : &:r226_1, r226_2 +# 227| r227_1(float) = Constant[2.0] : +# 227| r227_2(glval) = VariableAddress[z] : +# 227| r227_3(long) = Load : &:r227_2, ~m? +# 227| r227_4(float) = Convert : r227_3 +# 227| r227_5(float) = Add : r227_4, r227_1 +# 227| r227_6(long) = Convert : r227_5 +# 227| mu227_7(long) = Store : &:r227_2, r227_6 +# 228| v228_1(void) = NoOp : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 230| void UninitializedVariables() # 230| Block 0 -# 230| v230_1(void) = EnterFunction : -# 230| mu230_2(unknown) = AliasedDefinition : -# 230| mu230_3(unknown) = InitializeNonLocal : -# 230| mu230_4(unknown) = UnmodeledDefinition : -# 231| r231_1(glval) = VariableAddress[x] : -# 231| mu231_2(int) = Uninitialized[x] : &:r231_1 -# 232| r232_1(glval) = VariableAddress[y] : -# 232| r232_2(glval) = VariableAddress[x] : -# 232| r232_3(int) = Load : &:r232_2, ~mu230_4 -# 232| mu232_4(int) = Store : &:r232_1, r232_3 -# 233| v233_1(void) = NoOp : -# 230| v230_5(void) = ReturnVoid : -# 230| v230_6(void) = UnmodeledUse : mu* -# 230| v230_7(void) = AliasedUse : ~mu230_4 -# 230| v230_8(void) = ExitFunction : +# 230| v230_1(void) = EnterFunction : +# 230| mu230_2(unknown) = AliasedDefinition : +# 230| mu230_3(unknown) = InitializeNonLocal : +# 231| r231_1(glval) = VariableAddress[x] : +# 231| mu231_2(int) = Uninitialized[x] : &:r231_1 +# 232| r232_1(glval) = VariableAddress[y] : +# 232| r232_2(glval) = VariableAddress[x] : +# 232| r232_3(int) = Load : &:r232_2, ~m? +# 232| mu232_4(int) = Store : &:r232_1, r232_3 +# 233| v233_1(void) = NoOp : +# 230| v230_4(void) = ReturnVoid : +# 230| v230_5(void) = AliasedUse : ~m? +# 230| v230_6(void) = ExitFunction : # 235| int Parameters(int, int) # 235| Block 0 # 235| v235_1(void) = EnterFunction : # 235| mu235_2(unknown) = AliasedDefinition : # 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = VariableAddress[x] : -# 235| mu235_6(int) = InitializeParameter[x] : &:r235_5 -# 235| r235_7(glval) = VariableAddress[y] : -# 235| mu235_8(int) = InitializeParameter[y] : &:r235_7 +# 235| r235_4(glval) = VariableAddress[x] : +# 235| mu235_5(int) = InitializeParameter[x] : &:r235_4 +# 235| r235_6(glval) = VariableAddress[y] : +# 235| mu235_7(int) = InitializeParameter[y] : &:r235_6 # 236| r236_1(glval) = VariableAddress[#return] : # 236| r236_2(glval) = VariableAddress[x] : -# 236| r236_3(int) = Load : &:r236_2, ~mu235_4 +# 236| r236_3(int) = Load : &:r236_2, ~m? # 236| r236_4(glval) = VariableAddress[y] : -# 236| r236_5(int) = Load : &:r236_4, ~mu235_4 +# 236| r236_5(int) = Load : &:r236_4, ~m? # 236| r236_6(int) = Rem : r236_3, r236_5 # 236| mu236_7(int) = Store : &:r236_1, r236_6 -# 235| r235_9(glval) = VariableAddress[#return] : -# 235| v235_10(void) = ReturnValue : &:r235_9, ~mu235_4 -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : ~mu235_4 -# 235| v235_13(void) = ExitFunction : +# 235| r235_8(glval) = VariableAddress[#return] : +# 235| v235_9(void) = ReturnValue : &:r235_8, ~m? +# 235| v235_10(void) = AliasedUse : ~m? +# 235| v235_11(void) = ExitFunction : # 239| void IfStatements(bool, int, int) # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : -# 239| r239_5(glval) = VariableAddress[b] : -# 239| mu239_6(bool) = InitializeParameter[b] : &:r239_5 -# 239| r239_7(glval) = VariableAddress[x] : -# 239| mu239_8(int) = InitializeParameter[x] : &:r239_7 -# 239| r239_9(glval) = VariableAddress[y] : -# 239| mu239_10(int) = InitializeParameter[y] : &:r239_9 +# 239| r239_4(glval) = VariableAddress[b] : +# 239| mu239_5(bool) = InitializeParameter[b] : &:r239_4 +# 239| r239_6(glval) = VariableAddress[x] : +# 239| mu239_7(int) = InitializeParameter[x] : &:r239_6 +# 239| r239_8(glval) = VariableAddress[y] : +# 239| mu239_9(int) = InitializeParameter[y] : &:r239_8 # 240| r240_1(glval) = VariableAddress[b] : -# 240| r240_2(bool) = Load : &:r240_1, ~mu239_4 +# 240| r240_2(bool) = Load : &:r240_1, ~m? # 240| v240_3(void) = ConditionalBranch : r240_2 #-----| False -> Block 1 #-----| True -> Block 7 # 243| Block 1 # 243| r243_1(glval) = VariableAddress[b] : -# 243| r243_2(bool) = Load : &:r243_1, ~mu239_4 +# 243| r243_2(bool) = Load : &:r243_1, ~m? # 243| v243_3(void) = ConditionalBranch : r243_2 #-----| False -> Block 3 #-----| True -> Block 2 # 244| Block 2 # 244| r244_1(glval) = VariableAddress[y] : -# 244| r244_2(int) = Load : &:r244_1, ~mu239_4 +# 244| r244_2(int) = Load : &:r244_1, ~m? # 244| r244_3(glval) = VariableAddress[x] : # 244| mu244_4(int) = Store : &:r244_3, r244_2 #-----| Goto -> Block 3 # 247| Block 3 # 247| r247_1(glval) = VariableAddress[x] : -# 247| r247_2(int) = Load : &:r247_1, ~mu239_4 +# 247| r247_2(int) = Load : &:r247_1, ~m? # 247| r247_3(int) = Constant[7] : # 247| r247_4(bool) = CompareLT : r247_2, r247_3 # 247| v247_5(void) = ConditionalBranch : r247_4 @@ -1795,10 +1751,9 @@ ir.cpp: # 251| Block 6 # 251| v251_1(void) = NoOp : -# 239| v239_11(void) = ReturnVoid : -# 239| v239_12(void) = UnmodeledUse : mu* -# 239| v239_13(void) = AliasedUse : ~mu239_4 -# 239| v239_14(void) = ExitFunction : +# 239| v239_10(void) = ReturnVoid : +# 239| v239_11(void) = AliasedUse : ~m? +# 239| v239_12(void) = ExitFunction : # 240| Block 7 # 240| v240_4(void) = NoOp : @@ -1809,29 +1764,27 @@ ir.cpp: # 253| v253_1(void) = EnterFunction : # 253| mu253_2(unknown) = AliasedDefinition : # 253| mu253_3(unknown) = InitializeNonLocal : -# 253| mu253_4(unknown) = UnmodeledDefinition : -# 253| r253_5(glval) = VariableAddress[n] : -# 253| mu253_6(int) = InitializeParameter[n] : &:r253_5 +# 253| r253_4(glval) = VariableAddress[n] : +# 253| mu253_5(int) = InitializeParameter[n] : &:r253_4 #-----| Goto -> Block 3 # 255| Block 1 # 255| r255_1(int) = Constant[1] : # 255| r255_2(glval) = VariableAddress[n] : -# 255| r255_3(int) = Load : &:r255_2, ~mu253_4 +# 255| r255_3(int) = Load : &:r255_2, ~m? # 255| r255_4(int) = Sub : r255_3, r255_1 # 255| mu255_5(int) = Store : &:r255_2, r255_4 #-----| Goto (back edge) -> Block 3 # 257| Block 2 -# 257| v257_1(void) = NoOp : -# 253| v253_7(void) = ReturnVoid : -# 253| v253_8(void) = UnmodeledUse : mu* -# 253| v253_9(void) = AliasedUse : ~mu253_4 -# 253| v253_10(void) = ExitFunction : +# 257| v257_1(void) = NoOp : +# 253| v253_6(void) = ReturnVoid : +# 253| v253_7(void) = AliasedUse : ~m? +# 253| v253_8(void) = ExitFunction : # 254| Block 3 # 254| r254_1(glval) = VariableAddress[n] : -# 254| r254_2(int) = Load : &:r254_1, ~mu253_4 +# 254| r254_2(int) = Load : &:r254_1, ~m? # 254| r254_3(int) = Constant[0] : # 254| r254_4(bool) = CompareGT : r254_2, r254_3 # 254| v254_5(void) = ConditionalBranch : r254_4 @@ -1843,19 +1796,18 @@ ir.cpp: # 259| v259_1(void) = EnterFunction : # 259| mu259_2(unknown) = AliasedDefinition : # 259| mu259_3(unknown) = InitializeNonLocal : -# 259| mu259_4(unknown) = UnmodeledDefinition : -# 259| r259_5(glval) = VariableAddress[n] : -# 259| mu259_6(int) = InitializeParameter[n] : &:r259_5 +# 259| r259_4(glval) = VariableAddress[n] : +# 259| mu259_5(int) = InitializeParameter[n] : &:r259_4 #-----| Goto -> Block 1 # 261| Block 1 # 261| r261_1(int) = Constant[1] : # 261| r261_2(glval) = VariableAddress[n] : -# 261| r261_3(int) = Load : &:r261_2, ~mu259_4 +# 261| r261_3(int) = Load : &:r261_2, ~m? # 261| r261_4(int) = Sub : r261_3, r261_1 # 261| mu261_5(int) = Store : &:r261_2, r261_4 # 262| r262_1(glval) = VariableAddress[n] : -# 262| r262_2(int) = Load : &:r262_1, ~mu259_4 +# 262| r262_2(int) = Load : &:r262_1, ~m? # 262| r262_3(int) = Constant[0] : # 262| r262_4(bool) = CompareGT : r262_2, r262_3 # 262| v262_5(void) = ConditionalBranch : r262_4 @@ -1863,27 +1815,24 @@ ir.cpp: #-----| True (back edge) -> Block 1 # 263| Block 2 -# 263| v263_1(void) = NoOp : -# 259| v259_7(void) = ReturnVoid : -# 259| v259_8(void) = UnmodeledUse : mu* -# 259| v259_9(void) = AliasedUse : ~mu259_4 -# 259| v259_10(void) = ExitFunction : +# 263| v263_1(void) = NoOp : +# 259| v259_6(void) = ReturnVoid : +# 259| v259_7(void) = AliasedUse : ~m? +# 259| v259_8(void) = ExitFunction : # 265| void For_Empty() # 265| Block 0 -# 265| v265_1(void) = EnterFunction : -# 265| mu265_2(unknown) = AliasedDefinition : -# 265| mu265_3(unknown) = InitializeNonLocal : -# 265| mu265_4(unknown) = UnmodeledDefinition : -# 266| r266_1(glval) = VariableAddress[j] : -# 266| mu266_2(int) = Uninitialized[j] : &:r266_1 +# 265| v265_1(void) = EnterFunction : +# 265| mu265_2(unknown) = AliasedDefinition : +# 265| mu265_3(unknown) = InitializeNonLocal : +# 266| r266_1(glval) = VariableAddress[j] : +# 266| mu266_2(int) = Uninitialized[j] : &:r266_1 #-----| Goto -> Block 2 # 265| Block 1 -# 265| v265_5(void) = ReturnVoid : -# 265| v265_6(void) = UnmodeledUse : mu* -# 265| v265_7(void) = AliasedUse : ~mu265_4 -# 265| v265_8(void) = ExitFunction : +# 265| v265_4(void) = ReturnVoid : +# 265| v265_5(void) = AliasedUse : ~m? +# 265| v265_6(void) = ExitFunction : # 268| Block 2 # 268| v268_1(void) = NoOp : @@ -1891,20 +1840,18 @@ ir.cpp: # 272| void For_Init() # 272| Block 0 -# 272| v272_1(void) = EnterFunction : -# 272| mu272_2(unknown) = AliasedDefinition : -# 272| mu272_3(unknown) = InitializeNonLocal : -# 272| mu272_4(unknown) = UnmodeledDefinition : -# 273| r273_1(glval) = VariableAddress[i] : -# 273| r273_2(int) = Constant[0] : -# 273| mu273_3(int) = Store : &:r273_1, r273_2 +# 272| v272_1(void) = EnterFunction : +# 272| mu272_2(unknown) = AliasedDefinition : +# 272| mu272_3(unknown) = InitializeNonLocal : +# 273| r273_1(glval) = VariableAddress[i] : +# 273| r273_2(int) = Constant[0] : +# 273| mu273_3(int) = Store : &:r273_1, r273_2 #-----| Goto -> Block 2 # 272| Block 1 -# 272| v272_5(void) = ReturnVoid : -# 272| v272_6(void) = UnmodeledUse : mu* -# 272| v272_7(void) = AliasedUse : ~mu272_4 -# 272| v272_8(void) = ExitFunction : +# 272| v272_4(void) = ReturnVoid : +# 272| v272_5(void) = AliasedUse : ~m? +# 272| v272_6(void) = ExitFunction : # 274| Block 2 # 274| v274_1(void) = NoOp : @@ -1912,18 +1859,17 @@ ir.cpp: # 278| void For_Condition() # 278| Block 0 -# 278| v278_1(void) = EnterFunction : -# 278| mu278_2(unknown) = AliasedDefinition : -# 278| mu278_3(unknown) = InitializeNonLocal : -# 278| mu278_4(unknown) = UnmodeledDefinition : -# 279| r279_1(glval) = VariableAddress[i] : -# 279| r279_2(int) = Constant[0] : -# 279| mu279_3(int) = Store : &:r279_1, r279_2 +# 278| v278_1(void) = EnterFunction : +# 278| mu278_2(unknown) = AliasedDefinition : +# 278| mu278_3(unknown) = InitializeNonLocal : +# 279| r279_1(glval) = VariableAddress[i] : +# 279| r279_2(int) = Constant[0] : +# 279| mu279_3(int) = Store : &:r279_1, r279_2 #-----| Goto -> Block 1 # 280| Block 1 # 280| r280_1(glval) = VariableAddress[i] : -# 280| r280_2(int) = Load : &:r280_1, ~mu278_4 +# 280| r280_2(int) = Load : &:r280_1, ~m? # 280| r280_3(int) = Constant[10] : # 280| r280_4(bool) = CompareLT : r280_2, r280_3 # 280| v280_5(void) = ConditionalBranch : r280_4 @@ -1936,51 +1882,47 @@ ir.cpp: # 283| Block 3 # 283| v283_1(void) = NoOp : -# 278| v278_5(void) = ReturnVoid : -# 278| v278_6(void) = UnmodeledUse : mu* -# 278| v278_7(void) = AliasedUse : ~mu278_4 -# 278| v278_8(void) = ExitFunction : +# 278| v278_4(void) = ReturnVoid : +# 278| v278_5(void) = AliasedUse : ~m? +# 278| v278_6(void) = ExitFunction : # 285| void For_Update() # 285| Block 0 -# 285| v285_1(void) = EnterFunction : -# 285| mu285_2(unknown) = AliasedDefinition : -# 285| mu285_3(unknown) = InitializeNonLocal : -# 285| mu285_4(unknown) = UnmodeledDefinition : -# 286| r286_1(glval) = VariableAddress[i] : -# 286| r286_2(int) = Constant[0] : -# 286| mu286_3(int) = Store : &:r286_1, r286_2 +# 285| v285_1(void) = EnterFunction : +# 285| mu285_2(unknown) = AliasedDefinition : +# 285| mu285_3(unknown) = InitializeNonLocal : +# 286| r286_1(glval) = VariableAddress[i] : +# 286| r286_2(int) = Constant[0] : +# 286| mu286_3(int) = Store : &:r286_1, r286_2 #-----| Goto -> Block 2 # 285| Block 1 -# 285| v285_5(void) = ReturnVoid : -# 285| v285_6(void) = UnmodeledUse : mu* -# 285| v285_7(void) = AliasedUse : ~mu285_4 -# 285| v285_8(void) = ExitFunction : +# 285| v285_4(void) = ReturnVoid : +# 285| v285_5(void) = AliasedUse : ~m? +# 285| v285_6(void) = ExitFunction : # 288| Block 2 # 288| v288_1(void) = NoOp : # 287| r287_1(int) = Constant[1] : # 287| r287_2(glval) = VariableAddress[i] : -# 287| r287_3(int) = Load : &:r287_2, ~mu285_4 +# 287| r287_3(int) = Load : &:r287_2, ~m? # 287| r287_4(int) = Add : r287_3, r287_1 # 287| mu287_5(int) = Store : &:r287_2, r287_4 #-----| Goto (back edge) -> Block 2 # 292| void For_InitCondition() # 292| Block 0 -# 292| v292_1(void) = EnterFunction : -# 292| mu292_2(unknown) = AliasedDefinition : -# 292| mu292_3(unknown) = InitializeNonLocal : -# 292| mu292_4(unknown) = UnmodeledDefinition : -# 293| r293_1(glval) = VariableAddress[i] : -# 293| r293_2(int) = Constant[0] : -# 293| mu293_3(int) = Store : &:r293_1, r293_2 +# 292| v292_1(void) = EnterFunction : +# 292| mu292_2(unknown) = AliasedDefinition : +# 292| mu292_3(unknown) = InitializeNonLocal : +# 293| r293_1(glval) = VariableAddress[i] : +# 293| r293_2(int) = Constant[0] : +# 293| mu293_3(int) = Store : &:r293_1, r293_2 #-----| Goto -> Block 1 # 293| Block 1 # 293| r293_4(glval) = VariableAddress[i] : -# 293| r293_5(int) = Load : &:r293_4, ~mu292_4 +# 293| r293_5(int) = Load : &:r293_4, ~m? # 293| r293_6(int) = Constant[10] : # 293| r293_7(bool) = CompareLT : r293_5, r293_6 # 293| v293_8(void) = ConditionalBranch : r293_7 @@ -1993,51 +1935,47 @@ ir.cpp: # 296| Block 3 # 296| v296_1(void) = NoOp : -# 292| v292_5(void) = ReturnVoid : -# 292| v292_6(void) = UnmodeledUse : mu* -# 292| v292_7(void) = AliasedUse : ~mu292_4 -# 292| v292_8(void) = ExitFunction : +# 292| v292_4(void) = ReturnVoid : +# 292| v292_5(void) = AliasedUse : ~m? +# 292| v292_6(void) = ExitFunction : # 298| void For_InitUpdate() # 298| Block 0 -# 298| v298_1(void) = EnterFunction : -# 298| mu298_2(unknown) = AliasedDefinition : -# 298| mu298_3(unknown) = InitializeNonLocal : -# 298| mu298_4(unknown) = UnmodeledDefinition : -# 299| r299_1(glval) = VariableAddress[i] : -# 299| r299_2(int) = Constant[0] : -# 299| mu299_3(int) = Store : &:r299_1, r299_2 +# 298| v298_1(void) = EnterFunction : +# 298| mu298_2(unknown) = AliasedDefinition : +# 298| mu298_3(unknown) = InitializeNonLocal : +# 299| r299_1(glval) = VariableAddress[i] : +# 299| r299_2(int) = Constant[0] : +# 299| mu299_3(int) = Store : &:r299_1, r299_2 #-----| Goto -> Block 2 # 298| Block 1 -# 298| v298_5(void) = ReturnVoid : -# 298| v298_6(void) = UnmodeledUse : mu* -# 298| v298_7(void) = AliasedUse : ~mu298_4 -# 298| v298_8(void) = ExitFunction : +# 298| v298_4(void) = ReturnVoid : +# 298| v298_5(void) = AliasedUse : ~m? +# 298| v298_6(void) = ExitFunction : # 300| Block 2 # 300| v300_1(void) = NoOp : # 299| r299_4(int) = Constant[1] : # 299| r299_5(glval) = VariableAddress[i] : -# 299| r299_6(int) = Load : &:r299_5, ~mu298_4 +# 299| r299_6(int) = Load : &:r299_5, ~m? # 299| r299_7(int) = Add : r299_6, r299_4 # 299| mu299_8(int) = Store : &:r299_5, r299_7 #-----| Goto (back edge) -> Block 2 # 304| void For_ConditionUpdate() # 304| Block 0 -# 304| v304_1(void) = EnterFunction : -# 304| mu304_2(unknown) = AliasedDefinition : -# 304| mu304_3(unknown) = InitializeNonLocal : -# 304| mu304_4(unknown) = UnmodeledDefinition : -# 305| r305_1(glval) = VariableAddress[i] : -# 305| r305_2(int) = Constant[0] : -# 305| mu305_3(int) = Store : &:r305_1, r305_2 +# 304| v304_1(void) = EnterFunction : +# 304| mu304_2(unknown) = AliasedDefinition : +# 304| mu304_3(unknown) = InitializeNonLocal : +# 305| r305_1(glval) = VariableAddress[i] : +# 305| r305_2(int) = Constant[0] : +# 305| mu305_3(int) = Store : &:r305_1, r305_2 #-----| Goto -> Block 1 # 306| Block 1 # 306| r306_1(glval) = VariableAddress[i] : -# 306| r306_2(int) = Load : &:r306_1, ~mu304_4 +# 306| r306_2(int) = Load : &:r306_1, ~m? # 306| r306_3(int) = Constant[10] : # 306| r306_4(bool) = CompareLT : r306_2, r306_3 # 306| v306_5(void) = ConditionalBranch : r306_4 @@ -2048,32 +1986,30 @@ ir.cpp: # 307| v307_1(void) = NoOp : # 306| r306_6(int) = Constant[1] : # 306| r306_7(glval) = VariableAddress[i] : -# 306| r306_8(int) = Load : &:r306_7, ~mu304_4 +# 306| r306_8(int) = Load : &:r306_7, ~m? # 306| r306_9(int) = Add : r306_8, r306_6 # 306| mu306_10(int) = Store : &:r306_7, r306_9 #-----| Goto (back edge) -> Block 1 # 309| Block 3 # 309| v309_1(void) = NoOp : -# 304| v304_5(void) = ReturnVoid : -# 304| v304_6(void) = UnmodeledUse : mu* -# 304| v304_7(void) = AliasedUse : ~mu304_4 -# 304| v304_8(void) = ExitFunction : +# 304| v304_4(void) = ReturnVoid : +# 304| v304_5(void) = AliasedUse : ~m? +# 304| v304_6(void) = ExitFunction : # 311| void For_InitConditionUpdate() # 311| Block 0 -# 311| v311_1(void) = EnterFunction : -# 311| mu311_2(unknown) = AliasedDefinition : -# 311| mu311_3(unknown) = InitializeNonLocal : -# 311| mu311_4(unknown) = UnmodeledDefinition : -# 312| r312_1(glval) = VariableAddress[i] : -# 312| r312_2(int) = Constant[0] : -# 312| mu312_3(int) = Store : &:r312_1, r312_2 +# 311| v311_1(void) = EnterFunction : +# 311| mu311_2(unknown) = AliasedDefinition : +# 311| mu311_3(unknown) = InitializeNonLocal : +# 312| r312_1(glval) = VariableAddress[i] : +# 312| r312_2(int) = Constant[0] : +# 312| mu312_3(int) = Store : &:r312_1, r312_2 #-----| Goto -> Block 1 # 312| Block 1 # 312| r312_4(glval) = VariableAddress[i] : -# 312| r312_5(int) = Load : &:r312_4, ~mu311_4 +# 312| r312_5(int) = Load : &:r312_4, ~m? # 312| r312_6(int) = Constant[10] : # 312| r312_7(bool) = CompareLT : r312_5, r312_6 # 312| v312_8(void) = ConditionalBranch : r312_7 @@ -2084,32 +2020,30 @@ ir.cpp: # 313| v313_1(void) = NoOp : # 312| r312_9(int) = Constant[1] : # 312| r312_10(glval) = VariableAddress[i] : -# 312| r312_11(int) = Load : &:r312_10, ~mu311_4 +# 312| r312_11(int) = Load : &:r312_10, ~m? # 312| r312_12(int) = Add : r312_11, r312_9 # 312| mu312_13(int) = Store : &:r312_10, r312_12 #-----| Goto (back edge) -> Block 1 # 315| Block 3 # 315| v315_1(void) = NoOp : -# 311| v311_5(void) = ReturnVoid : -# 311| v311_6(void) = UnmodeledUse : mu* -# 311| v311_7(void) = AliasedUse : ~mu311_4 -# 311| v311_8(void) = ExitFunction : +# 311| v311_4(void) = ReturnVoid : +# 311| v311_5(void) = AliasedUse : ~m? +# 311| v311_6(void) = ExitFunction : # 317| void For_Break() # 317| Block 0 -# 317| v317_1(void) = EnterFunction : -# 317| mu317_2(unknown) = AliasedDefinition : -# 317| mu317_3(unknown) = InitializeNonLocal : -# 317| mu317_4(unknown) = UnmodeledDefinition : -# 318| r318_1(glval) = VariableAddress[i] : -# 318| r318_2(int) = Constant[0] : -# 318| mu318_3(int) = Store : &:r318_1, r318_2 +# 317| v317_1(void) = EnterFunction : +# 317| mu317_2(unknown) = AliasedDefinition : +# 317| mu317_3(unknown) = InitializeNonLocal : +# 318| r318_1(glval) = VariableAddress[i] : +# 318| r318_2(int) = Constant[0] : +# 318| mu318_3(int) = Store : &:r318_1, r318_2 #-----| Goto -> Block 1 # 318| Block 1 # 318| r318_4(glval) = VariableAddress[i] : -# 318| r318_5(int) = Load : &:r318_4, ~mu317_4 +# 318| r318_5(int) = Load : &:r318_4, ~m? # 318| r318_6(int) = Constant[10] : # 318| r318_7(bool) = CompareLT : r318_5, r318_6 # 318| v318_8(void) = ConditionalBranch : r318_7 @@ -2119,14 +2053,14 @@ ir.cpp: # 318| Block 2 # 318| r318_9(int) = Constant[1] : # 318| r318_10(glval) = VariableAddress[i] : -# 318| r318_11(int) = Load : &:r318_10, ~mu317_4 +# 318| r318_11(int) = Load : &:r318_10, ~m? # 318| r318_12(int) = Add : r318_11, r318_9 # 318| mu318_13(int) = Store : &:r318_10, r318_12 #-----| Goto (back edge) -> Block 1 # 319| Block 3 # 319| r319_1(glval) = VariableAddress[i] : -# 319| r319_2(int) = Load : &:r319_1, ~mu317_4 +# 319| r319_2(int) = Load : &:r319_1, ~m? # 319| r319_3(int) = Constant[5] : # 319| r319_4(bool) = CompareEQ : r319_2, r319_3 # 319| v319_5(void) = ConditionalBranch : r319_4 @@ -2140,25 +2074,23 @@ ir.cpp: # 322| Block 5 # 322| v322_1(void) = NoOp : # 323| v323_1(void) = NoOp : -# 317| v317_5(void) = ReturnVoid : -# 317| v317_6(void) = UnmodeledUse : mu* -# 317| v317_7(void) = AliasedUse : ~mu317_4 -# 317| v317_8(void) = ExitFunction : +# 317| v317_4(void) = ReturnVoid : +# 317| v317_5(void) = AliasedUse : ~m? +# 317| v317_6(void) = ExitFunction : # 325| void For_Continue_Update() # 325| Block 0 -# 325| v325_1(void) = EnterFunction : -# 325| mu325_2(unknown) = AliasedDefinition : -# 325| mu325_3(unknown) = InitializeNonLocal : -# 325| mu325_4(unknown) = UnmodeledDefinition : -# 326| r326_1(glval) = VariableAddress[i] : -# 326| r326_2(int) = Constant[0] : -# 326| mu326_3(int) = Store : &:r326_1, r326_2 +# 325| v325_1(void) = EnterFunction : +# 325| mu325_2(unknown) = AliasedDefinition : +# 325| mu325_3(unknown) = InitializeNonLocal : +# 326| r326_1(glval) = VariableAddress[i] : +# 326| r326_2(int) = Constant[0] : +# 326| mu326_3(int) = Store : &:r326_1, r326_2 #-----| Goto -> Block 1 # 326| Block 1 # 326| r326_4(glval) = VariableAddress[i] : -# 326| r326_5(int) = Load : &:r326_4, ~mu325_4 +# 326| r326_5(int) = Load : &:r326_4, ~m? # 326| r326_6(int) = Constant[10] : # 326| r326_7(bool) = CompareLT : r326_5, r326_6 # 326| v326_8(void) = ConditionalBranch : r326_7 @@ -2167,7 +2099,7 @@ ir.cpp: # 327| Block 2 # 327| r327_1(glval) = VariableAddress[i] : -# 327| r327_2(int) = Load : &:r327_1, ~mu325_4 +# 327| r327_2(int) = Load : &:r327_1, ~m? # 327| r327_3(int) = Constant[5] : # 327| r327_4(bool) = CompareEQ : r327_2, r327_3 # 327| v327_5(void) = ConditionalBranch : r327_4 @@ -2182,32 +2114,30 @@ ir.cpp: # 326| v326_9(void) = NoOp : # 326| r326_10(int) = Constant[1] : # 326| r326_11(glval) = VariableAddress[i] : -# 326| r326_12(int) = Load : &:r326_11, ~mu325_4 +# 326| r326_12(int) = Load : &:r326_11, ~m? # 326| r326_13(int) = Add : r326_12, r326_10 # 326| mu326_14(int) = Store : &:r326_11, r326_13 #-----| Goto (back edge) -> Block 1 # 331| Block 5 # 331| v331_1(void) = NoOp : -# 325| v325_5(void) = ReturnVoid : -# 325| v325_6(void) = UnmodeledUse : mu* -# 325| v325_7(void) = AliasedUse : ~mu325_4 -# 325| v325_8(void) = ExitFunction : +# 325| v325_4(void) = ReturnVoid : +# 325| v325_5(void) = AliasedUse : ~m? +# 325| v325_6(void) = ExitFunction : # 333| void For_Continue_NoUpdate() # 333| Block 0 -# 333| v333_1(void) = EnterFunction : -# 333| mu333_2(unknown) = AliasedDefinition : -# 333| mu333_3(unknown) = InitializeNonLocal : -# 333| mu333_4(unknown) = UnmodeledDefinition : -# 334| r334_1(glval) = VariableAddress[i] : -# 334| r334_2(int) = Constant[0] : -# 334| mu334_3(int) = Store : &:r334_1, r334_2 +# 333| v333_1(void) = EnterFunction : +# 333| mu333_2(unknown) = AliasedDefinition : +# 333| mu333_3(unknown) = InitializeNonLocal : +# 334| r334_1(glval) = VariableAddress[i] : +# 334| r334_2(int) = Constant[0] : +# 334| mu334_3(int) = Store : &:r334_1, r334_2 #-----| Goto -> Block 1 # 334| Block 1 # 334| r334_4(glval) = VariableAddress[i] : -# 334| r334_5(int) = Load : &:r334_4, ~mu333_4 +# 334| r334_5(int) = Load : &:r334_4, ~m? # 334| r334_6(int) = Constant[10] : # 334| r334_7(bool) = CompareLT : r334_5, r334_6 # 334| v334_8(void) = ConditionalBranch : r334_7 @@ -2216,7 +2146,7 @@ ir.cpp: # 335| Block 2 # 335| r335_1(glval) = VariableAddress[i] : -# 335| r335_2(int) = Load : &:r335_1, ~mu333_4 +# 335| r335_2(int) = Load : &:r335_1, ~m? # 335| r335_3(int) = Constant[5] : # 335| r335_4(bool) = CompareEQ : r335_2, r335_3 # 335| v335_5(void) = ConditionalBranch : r335_4 @@ -2233,67 +2163,61 @@ ir.cpp: # 339| Block 5 # 339| v339_1(void) = NoOp : -# 333| v333_5(void) = ReturnVoid : -# 333| v333_6(void) = UnmodeledUse : mu* -# 333| v333_7(void) = AliasedUse : ~mu333_4 -# 333| v333_8(void) = ExitFunction : +# 333| v333_4(void) = ReturnVoid : +# 333| v333_5(void) = AliasedUse : ~m? +# 333| v333_6(void) = ExitFunction : # 341| int Dereference(int*) # 341| Block 0 # 341| v341_1(void) = EnterFunction : # 341| mu341_2(unknown) = AliasedDefinition : # 341| mu341_3(unknown) = InitializeNonLocal : -# 341| mu341_4(unknown) = UnmodeledDefinition : -# 341| r341_5(glval) = VariableAddress[p] : -# 341| mu341_6(int *) = InitializeParameter[p] : &:r341_5 -# 341| r341_7(int *) = Load : &:r341_5, ~mu341_4 -# 341| mu341_8(unknown) = InitializeIndirection[p] : &:r341_7 +# 341| r341_4(glval) = VariableAddress[p] : +# 341| mu341_5(int *) = InitializeParameter[p] : &:r341_4 +# 341| r341_6(int *) = Load : &:r341_4, ~m? +# 341| mu341_7(unknown) = InitializeIndirection[p] : &:r341_6 # 342| r342_1(int) = Constant[1] : # 342| r342_2(glval) = VariableAddress[p] : -# 342| r342_3(int *) = Load : &:r342_2, ~mu341_4 +# 342| r342_3(int *) = Load : &:r342_2, ~m? # 342| r342_4(glval) = CopyValue : r342_3 # 342| mu342_5(int) = Store : &:r342_4, r342_1 # 343| r343_1(glval) = VariableAddress[#return] : # 343| r343_2(glval) = VariableAddress[p] : -# 343| r343_3(int *) = Load : &:r343_2, ~mu341_4 -# 343| r343_4(int) = Load : &:r343_3, ~mu341_4 +# 343| r343_3(int *) = Load : &:r343_2, ~m? +# 343| r343_4(int) = Load : &:r343_3, ~m? # 343| mu343_5(int) = Store : &:r343_1, r343_4 -# 341| v341_9(void) = ReturnIndirection[p] : &:r341_7, ~mu341_4 -# 341| r341_10(glval) = VariableAddress[#return] : -# 341| v341_11(void) = ReturnValue : &:r341_10, ~mu341_4 -# 341| v341_12(void) = UnmodeledUse : mu* -# 341| v341_13(void) = AliasedUse : ~mu341_4 -# 341| v341_14(void) = ExitFunction : +# 341| v341_8(void) = ReturnIndirection[p] : &:r341_6, ~m? +# 341| r341_9(glval) = VariableAddress[#return] : +# 341| v341_10(void) = ReturnValue : &:r341_9, ~m? +# 341| v341_11(void) = AliasedUse : ~m? +# 341| v341_12(void) = ExitFunction : # 348| int* AddressOf() # 348| Block 0 # 348| v348_1(void) = EnterFunction : # 348| mu348_2(unknown) = AliasedDefinition : # 348| mu348_3(unknown) = InitializeNonLocal : -# 348| mu348_4(unknown) = UnmodeledDefinition : # 349| r349_1(glval) = VariableAddress[#return] : # 349| r349_2(glval) = VariableAddress[g] : # 349| r349_3(int *) = CopyValue : r349_2 # 349| mu349_4(int *) = Store : &:r349_1, r349_3 -# 348| r348_5(glval) = VariableAddress[#return] : -# 348| v348_6(void) = ReturnValue : &:r348_5, ~mu348_4 -# 348| v348_7(void) = UnmodeledUse : mu* -# 348| v348_8(void) = AliasedUse : ~mu348_4 -# 348| v348_9(void) = ExitFunction : +# 348| r348_4(glval) = VariableAddress[#return] : +# 348| v348_5(void) = ReturnValue : &:r348_4, ~m? +# 348| v348_6(void) = AliasedUse : ~m? +# 348| v348_7(void) = ExitFunction : # 352| void Break(int) # 352| Block 0 # 352| v352_1(void) = EnterFunction : # 352| mu352_2(unknown) = AliasedDefinition : # 352| mu352_3(unknown) = InitializeNonLocal : -# 352| mu352_4(unknown) = UnmodeledDefinition : -# 352| r352_5(glval) = VariableAddress[n] : -# 352| mu352_6(int) = InitializeParameter[n] : &:r352_5 +# 352| r352_4(glval) = VariableAddress[n] : +# 352| mu352_5(int) = InitializeParameter[n] : &:r352_4 #-----| Goto -> Block 5 # 354| Block 1 # 354| r354_1(glval) = VariableAddress[n] : -# 354| r354_2(int) = Load : &:r354_1, ~mu352_4 +# 354| r354_2(int) = Load : &:r354_1, ~m? # 354| r354_3(int) = Constant[1] : # 354| r354_4(bool) = CompareEQ : r354_2, r354_3 # 354| v354_5(void) = ConditionalBranch : r354_4 @@ -2307,22 +2231,21 @@ ir.cpp: # 356| Block 3 # 356| r356_1(int) = Constant[1] : # 356| r356_2(glval) = VariableAddress[n] : -# 356| r356_3(int) = Load : &:r356_2, ~mu352_4 +# 356| r356_3(int) = Load : &:r356_2, ~m? # 356| r356_4(int) = Sub : r356_3, r356_1 # 356| mu356_5(int) = Store : &:r356_2, r356_4 #-----| Goto (back edge) -> Block 5 # 357| Block 4 -# 357| v357_1(void) = NoOp : -# 358| v358_1(void) = NoOp : -# 352| v352_7(void) = ReturnVoid : -# 352| v352_8(void) = UnmodeledUse : mu* -# 352| v352_9(void) = AliasedUse : ~mu352_4 -# 352| v352_10(void) = ExitFunction : +# 357| v357_1(void) = NoOp : +# 358| v358_1(void) = NoOp : +# 352| v352_6(void) = ReturnVoid : +# 352| v352_7(void) = AliasedUse : ~m? +# 352| v352_8(void) = ExitFunction : # 353| Block 5 # 353| r353_1(glval) = VariableAddress[n] : -# 353| r353_2(int) = Load : &:r353_1, ~mu352_4 +# 353| r353_2(int) = Load : &:r353_1, ~m? # 353| r353_3(int) = Constant[0] : # 353| r353_4(bool) = CompareGT : r353_2, r353_3 # 353| v353_5(void) = ConditionalBranch : r353_4 @@ -2334,14 +2257,13 @@ ir.cpp: # 360| v360_1(void) = EnterFunction : # 360| mu360_2(unknown) = AliasedDefinition : # 360| mu360_3(unknown) = InitializeNonLocal : -# 360| mu360_4(unknown) = UnmodeledDefinition : -# 360| r360_5(glval) = VariableAddress[n] : -# 360| mu360_6(int) = InitializeParameter[n] : &:r360_5 +# 360| r360_4(glval) = VariableAddress[n] : +# 360| mu360_5(int) = InitializeParameter[n] : &:r360_4 #-----| Goto -> Block 1 # 362| Block 1 # 362| r362_1(glval) = VariableAddress[n] : -# 362| r362_2(int) = Load : &:r362_1, ~mu360_4 +# 362| r362_2(int) = Load : &:r362_1, ~m? # 362| r362_3(int) = Constant[1] : # 362| r362_4(bool) = CompareEQ : r362_2, r362_3 # 362| v362_5(void) = ConditionalBranch : r362_4 @@ -2355,7 +2277,7 @@ ir.cpp: # 365| Block 3 # 365| r365_1(int) = Constant[1] : # 365| r365_2(glval) = VariableAddress[n] : -# 365| r365_3(int) = Load : &:r365_2, ~mu360_4 +# 365| r365_3(int) = Load : &:r365_2, ~m? # 365| r365_4(int) = Sub : r365_3, r365_1 # 365| mu365_5(int) = Store : &:r365_2, r365_4 #-----| Goto -> Block 4 @@ -2363,7 +2285,7 @@ ir.cpp: # 361| Block 4 # 361| v361_1(void) = NoOp : # 366| r366_1(glval) = VariableAddress[n] : -# 366| r366_2(int) = Load : &:r366_1, ~mu360_4 +# 366| r366_2(int) = Load : &:r366_1, ~m? # 366| r366_3(int) = Constant[0] : # 366| r366_4(bool) = CompareGT : r366_2, r366_3 # 366| v366_5(void) = ConditionalBranch : r366_4 @@ -2371,93 +2293,85 @@ ir.cpp: #-----| True (back edge) -> Block 1 # 367| Block 5 -# 367| v367_1(void) = NoOp : -# 360| v360_7(void) = ReturnVoid : -# 360| v360_8(void) = UnmodeledUse : mu* -# 360| v360_9(void) = AliasedUse : ~mu360_4 -# 360| v360_10(void) = ExitFunction : +# 367| v367_1(void) = NoOp : +# 360| v360_6(void) = ReturnVoid : +# 360| v360_7(void) = AliasedUse : ~m? +# 360| v360_8(void) = ExitFunction : # 372| void Call() # 372| Block 0 # 372| v372_1(void) = EnterFunction : # 372| mu372_2(unknown) = AliasedDefinition : # 372| mu372_3(unknown) = InitializeNonLocal : -# 372| mu372_4(unknown) = UnmodeledDefinition : # 373| r373_1(glval) = FunctionAddress[VoidFunc] : # 373| v373_2(void) = Call : func:r373_1 -# 373| mu373_3(unknown) = ^CallSideEffect : ~mu372_4 +# 373| mu373_3(unknown) = ^CallSideEffect : ~m? # 374| v374_1(void) = NoOp : -# 372| v372_5(void) = ReturnVoid : -# 372| v372_6(void) = UnmodeledUse : mu* -# 372| v372_7(void) = AliasedUse : ~mu372_4 -# 372| v372_8(void) = ExitFunction : +# 372| v372_4(void) = ReturnVoid : +# 372| v372_5(void) = AliasedUse : ~m? +# 372| v372_6(void) = ExitFunction : # 376| int CallAdd(int, int) # 376| Block 0 # 376| v376_1(void) = EnterFunction : # 376| mu376_2(unknown) = AliasedDefinition : # 376| mu376_3(unknown) = InitializeNonLocal : -# 376| mu376_4(unknown) = UnmodeledDefinition : -# 376| r376_5(glval) = VariableAddress[x] : -# 376| mu376_6(int) = InitializeParameter[x] : &:r376_5 -# 376| r376_7(glval) = VariableAddress[y] : -# 376| mu376_8(int) = InitializeParameter[y] : &:r376_7 +# 376| r376_4(glval) = VariableAddress[x] : +# 376| mu376_5(int) = InitializeParameter[x] : &:r376_4 +# 376| r376_6(glval) = VariableAddress[y] : +# 376| mu376_7(int) = InitializeParameter[y] : &:r376_6 # 377| r377_1(glval) = VariableAddress[#return] : # 377| r377_2(glval) = FunctionAddress[Add] : # 377| r377_3(glval) = VariableAddress[x] : -# 377| r377_4(int) = Load : &:r377_3, ~mu376_4 +# 377| r377_4(int) = Load : &:r377_3, ~m? # 377| r377_5(glval) = VariableAddress[y] : -# 377| r377_6(int) = Load : &:r377_5, ~mu376_4 +# 377| r377_6(int) = Load : &:r377_5, ~m? # 377| r377_7(int) = Call : func:r377_2, 0:r377_4, 1:r377_6 -# 377| mu377_8(unknown) = ^CallSideEffect : ~mu376_4 +# 377| mu377_8(unknown) = ^CallSideEffect : ~m? # 377| mu377_9(int) = Store : &:r377_1, r377_7 -# 376| r376_9(glval) = VariableAddress[#return] : -# 376| v376_10(void) = ReturnValue : &:r376_9, ~mu376_4 -# 376| v376_11(void) = UnmodeledUse : mu* -# 376| v376_12(void) = AliasedUse : ~mu376_4 -# 376| v376_13(void) = ExitFunction : +# 376| r376_8(glval) = VariableAddress[#return] : +# 376| v376_9(void) = ReturnValue : &:r376_8, ~m? +# 376| v376_10(void) = AliasedUse : ~m? +# 376| v376_11(void) = ExitFunction : # 380| int Comma(int, int) # 380| Block 0 # 380| v380_1(void) = EnterFunction : # 380| mu380_2(unknown) = AliasedDefinition : # 380| mu380_3(unknown) = InitializeNonLocal : -# 380| mu380_4(unknown) = UnmodeledDefinition : -# 380| r380_5(glval) = VariableAddress[x] : -# 380| mu380_6(int) = InitializeParameter[x] : &:r380_5 -# 380| r380_7(glval) = VariableAddress[y] : -# 380| mu380_8(int) = InitializeParameter[y] : &:r380_7 +# 380| r380_4(glval) = VariableAddress[x] : +# 380| mu380_5(int) = InitializeParameter[x] : &:r380_4 +# 380| r380_6(glval) = VariableAddress[y] : +# 380| mu380_7(int) = InitializeParameter[y] : &:r380_6 # 381| r381_1(glval) = VariableAddress[#return] : # 381| r381_2(glval) = FunctionAddress[VoidFunc] : # 381| v381_3(void) = Call : func:r381_2 -# 381| mu381_4(unknown) = ^CallSideEffect : ~mu380_4 +# 381| mu381_4(unknown) = ^CallSideEffect : ~m? # 381| r381_5(glval) = FunctionAddress[CallAdd] : # 381| r381_6(glval) = VariableAddress[x] : -# 381| r381_7(int) = Load : &:r381_6, ~mu380_4 +# 381| r381_7(int) = Load : &:r381_6, ~m? # 381| r381_8(glval) = VariableAddress[y] : -# 381| r381_9(int) = Load : &:r381_8, ~mu380_4 +# 381| r381_9(int) = Load : &:r381_8, ~m? # 381| r381_10(int) = Call : func:r381_5, 0:r381_7, 1:r381_9 -# 381| mu381_11(unknown) = ^CallSideEffect : ~mu380_4 +# 381| mu381_11(unknown) = ^CallSideEffect : ~m? # 381| r381_12(int) = CopyValue : r381_10 # 381| mu381_13(int) = Store : &:r381_1, r381_12 -# 380| r380_9(glval) = VariableAddress[#return] : -# 380| v380_10(void) = ReturnValue : &:r380_9, ~mu380_4 -# 380| v380_11(void) = UnmodeledUse : mu* -# 380| v380_12(void) = AliasedUse : ~mu380_4 -# 380| v380_13(void) = ExitFunction : +# 380| r380_8(glval) = VariableAddress[#return] : +# 380| v380_9(void) = ReturnValue : &:r380_8, ~m? +# 380| v380_10(void) = AliasedUse : ~m? +# 380| v380_11(void) = ExitFunction : # 384| void Switch(int) # 384| Block 0 # 384| v384_1(void) = EnterFunction : # 384| mu384_2(unknown) = AliasedDefinition : # 384| mu384_3(unknown) = InitializeNonLocal : -# 384| mu384_4(unknown) = UnmodeledDefinition : -# 384| r384_5(glval) = VariableAddress[x] : -# 384| mu384_6(int) = InitializeParameter[x] : &:r384_5 +# 384| r384_4(glval) = VariableAddress[x] : +# 384| mu384_5(int) = InitializeParameter[x] : &:r384_4 # 385| r385_1(glval) = VariableAddress[y] : # 385| mu385_2(int) = Uninitialized[y] : &:r385_1 # 386| r386_1(glval) = VariableAddress[x] : -# 386| r386_2(int) = Load : &:r386_1, ~mu384_4 +# 386| r386_2(int) = Load : &:r386_1, ~m? # 386| v386_3(void) = Switch : r386_2 #-----| Case[-1] -> Block 2 #-----| Case[1] -> Block 3 @@ -2522,37 +2436,33 @@ ir.cpp: #-----| Goto -> Block 9 # 409| Block 9 -# 409| v409_1(void) = NoOp : -# 410| v410_1(void) = NoOp : -# 384| v384_7(void) = ReturnVoid : -# 384| v384_8(void) = UnmodeledUse : mu* -# 384| v384_9(void) = AliasedUse : ~mu384_4 -# 384| v384_10(void) = ExitFunction : +# 409| v409_1(void) = NoOp : +# 410| v410_1(void) = NoOp : +# 384| v384_6(void) = ReturnVoid : +# 384| v384_7(void) = AliasedUse : ~m? +# 384| v384_8(void) = ExitFunction : # 422| Point ReturnStruct(Point) # 422| Block 0 # 422| v422_1(void) = EnterFunction : # 422| mu422_2(unknown) = AliasedDefinition : # 422| mu422_3(unknown) = InitializeNonLocal : -# 422| mu422_4(unknown) = UnmodeledDefinition : -# 422| r422_5(glval) = VariableAddress[pt] : -# 422| mu422_6(Point) = InitializeParameter[pt] : &:r422_5 +# 422| r422_4(glval) = VariableAddress[pt] : +# 422| mu422_5(Point) = InitializeParameter[pt] : &:r422_4 # 423| r423_1(glval) = VariableAddress[#return] : # 423| r423_2(glval) = VariableAddress[pt] : -# 423| r423_3(Point) = Load : &:r423_2, ~mu422_4 +# 423| r423_3(Point) = Load : &:r423_2, ~m? # 423| mu423_4(Point) = Store : &:r423_1, r423_3 -# 422| r422_7(glval) = VariableAddress[#return] : -# 422| v422_8(void) = ReturnValue : &:r422_7, ~mu422_4 -# 422| v422_9(void) = UnmodeledUse : mu* -# 422| v422_10(void) = AliasedUse : ~mu422_4 -# 422| v422_11(void) = ExitFunction : +# 422| r422_6(glval) = VariableAddress[#return] : +# 422| v422_7(void) = ReturnValue : &:r422_6, ~m? +# 422| v422_8(void) = AliasedUse : ~m? +# 422| v422_9(void) = ExitFunction : # 426| void FieldAccess() # 426| Block 0 # 426| v426_1(void) = EnterFunction : # 426| mu426_2(unknown) = AliasedDefinition : # 426| mu426_3(unknown) = InitializeNonLocal : -# 426| mu426_4(unknown) = UnmodeledDefinition : # 427| r427_1(glval) = VariableAddress[pt] : # 427| mu427_2(Point) = Uninitialized[pt] : &:r427_1 # 428| r428_1(int) = Constant[5] : @@ -2561,7 +2471,7 @@ ir.cpp: # 428| mu428_4(int) = Store : &:r428_3, r428_1 # 429| r429_1(glval) = VariableAddress[pt] : # 429| r429_2(glval) = FieldAddress[x] : r429_1 -# 429| r429_3(int) = Load : &:r429_2, ~mu426_4 +# 429| r429_3(int) = Load : &:r429_2, ~m? # 429| r429_4(glval) = VariableAddress[pt] : # 429| r429_5(glval) = FieldAddress[y] : r429_4 # 429| mu429_6(int) = Store : &:r429_5, r429_3 @@ -2571,32 +2481,30 @@ ir.cpp: # 430| r430_4(int *) = CopyValue : r430_3 # 430| mu430_5(int *) = Store : &:r430_1, r430_4 # 431| v431_1(void) = NoOp : -# 426| v426_5(void) = ReturnVoid : -# 426| v426_6(void) = UnmodeledUse : mu* -# 426| v426_7(void) = AliasedUse : ~mu426_4 -# 426| v426_8(void) = ExitFunction : +# 426| v426_4(void) = ReturnVoid : +# 426| v426_5(void) = AliasedUse : ~m? +# 426| v426_6(void) = ExitFunction : # 433| void LogicalOr(bool, bool) # 433| Block 0 # 433| v433_1(void) = EnterFunction : # 433| mu433_2(unknown) = AliasedDefinition : # 433| mu433_3(unknown) = InitializeNonLocal : -# 433| mu433_4(unknown) = UnmodeledDefinition : -# 433| r433_5(glval) = VariableAddress[a] : -# 433| mu433_6(bool) = InitializeParameter[a] : &:r433_5 -# 433| r433_7(glval) = VariableAddress[b] : -# 433| mu433_8(bool) = InitializeParameter[b] : &:r433_7 +# 433| r433_4(glval) = VariableAddress[a] : +# 433| mu433_5(bool) = InitializeParameter[a] : &:r433_4 +# 433| r433_6(glval) = VariableAddress[b] : +# 433| mu433_7(bool) = InitializeParameter[b] : &:r433_6 # 434| r434_1(glval) = VariableAddress[x] : # 434| mu434_2(int) = Uninitialized[x] : &:r434_1 # 435| r435_1(glval) = VariableAddress[a] : -# 435| r435_2(bool) = Load : &:r435_1, ~mu433_4 +# 435| r435_2(bool) = Load : &:r435_1, ~m? # 435| v435_3(void) = ConditionalBranch : r435_2 #-----| False -> Block 1 #-----| True -> Block 2 # 435| Block 1 # 435| r435_4(glval) = VariableAddress[b] : -# 435| r435_5(bool) = Load : &:r435_4, ~mu433_4 +# 435| r435_5(bool) = Load : &:r435_4, ~m? # 435| v435_6(void) = ConditionalBranch : r435_5 #-----| False -> Block 3 #-----| True -> Block 2 @@ -2609,14 +2517,14 @@ ir.cpp: # 439| Block 3 # 439| r439_1(glval) = VariableAddress[a] : -# 439| r439_2(bool) = Load : &:r439_1, ~mu433_4 +# 439| r439_2(bool) = Load : &:r439_1, ~m? # 439| v439_3(void) = ConditionalBranch : r439_2 #-----| False -> Block 4 #-----| True -> Block 5 # 439| Block 4 # 439| r439_4(glval) = VariableAddress[b] : -# 439| r439_5(bool) = Load : &:r439_4, ~mu433_4 +# 439| r439_5(bool) = Load : &:r439_4, ~m? # 439| v439_6(void) = ConditionalBranch : r439_5 #-----| False -> Block 6 #-----| True -> Block 5 @@ -2635,32 +2543,30 @@ ir.cpp: # 445| Block 7 # 445| v445_1(void) = NoOp : -# 433| v433_9(void) = ReturnVoid : -# 433| v433_10(void) = UnmodeledUse : mu* -# 433| v433_11(void) = AliasedUse : ~mu433_4 -# 433| v433_12(void) = ExitFunction : +# 433| v433_8(void) = ReturnVoid : +# 433| v433_9(void) = AliasedUse : ~m? +# 433| v433_10(void) = ExitFunction : # 447| void LogicalAnd(bool, bool) # 447| Block 0 # 447| v447_1(void) = EnterFunction : # 447| mu447_2(unknown) = AliasedDefinition : # 447| mu447_3(unknown) = InitializeNonLocal : -# 447| mu447_4(unknown) = UnmodeledDefinition : -# 447| r447_5(glval) = VariableAddress[a] : -# 447| mu447_6(bool) = InitializeParameter[a] : &:r447_5 -# 447| r447_7(glval) = VariableAddress[b] : -# 447| mu447_8(bool) = InitializeParameter[b] : &:r447_7 +# 447| r447_4(glval) = VariableAddress[a] : +# 447| mu447_5(bool) = InitializeParameter[a] : &:r447_4 +# 447| r447_6(glval) = VariableAddress[b] : +# 447| mu447_7(bool) = InitializeParameter[b] : &:r447_6 # 448| r448_1(glval) = VariableAddress[x] : # 448| mu448_2(int) = Uninitialized[x] : &:r448_1 # 449| r449_1(glval) = VariableAddress[a] : -# 449| r449_2(bool) = Load : &:r449_1, ~mu447_4 +# 449| r449_2(bool) = Load : &:r449_1, ~m? # 449| v449_3(void) = ConditionalBranch : r449_2 #-----| False -> Block 3 #-----| True -> Block 1 # 449| Block 1 # 449| r449_4(glval) = VariableAddress[b] : -# 449| r449_5(bool) = Load : &:r449_4, ~mu447_4 +# 449| r449_5(bool) = Load : &:r449_4, ~m? # 449| v449_6(void) = ConditionalBranch : r449_5 #-----| False -> Block 3 #-----| True -> Block 2 @@ -2673,14 +2579,14 @@ ir.cpp: # 453| Block 3 # 453| r453_1(glval) = VariableAddress[a] : -# 453| r453_2(bool) = Load : &:r453_1, ~mu447_4 +# 453| r453_2(bool) = Load : &:r453_1, ~m? # 453| v453_3(void) = ConditionalBranch : r453_2 #-----| False -> Block 6 #-----| True -> Block 4 # 453| Block 4 # 453| r453_4(glval) = VariableAddress[b] : -# 453| r453_5(bool) = Load : &:r453_4, ~mu447_4 +# 453| r453_5(bool) = Load : &:r453_4, ~m? # 453| v453_6(void) = ConditionalBranch : r453_5 #-----| False -> Block 6 #-----| True -> Block 5 @@ -2699,25 +2605,23 @@ ir.cpp: # 459| Block 7 # 459| v459_1(void) = NoOp : -# 447| v447_9(void) = ReturnVoid : -# 447| v447_10(void) = UnmodeledUse : mu* -# 447| v447_11(void) = AliasedUse : ~mu447_4 -# 447| v447_12(void) = ExitFunction : +# 447| v447_8(void) = ReturnVoid : +# 447| v447_9(void) = AliasedUse : ~m? +# 447| v447_10(void) = ExitFunction : # 461| void LogicalNot(bool, bool) # 461| Block 0 # 461| v461_1(void) = EnterFunction : # 461| mu461_2(unknown) = AliasedDefinition : # 461| mu461_3(unknown) = InitializeNonLocal : -# 461| mu461_4(unknown) = UnmodeledDefinition : -# 461| r461_5(glval) = VariableAddress[a] : -# 461| mu461_6(bool) = InitializeParameter[a] : &:r461_5 -# 461| r461_7(glval) = VariableAddress[b] : -# 461| mu461_8(bool) = InitializeParameter[b] : &:r461_7 +# 461| r461_4(glval) = VariableAddress[a] : +# 461| mu461_5(bool) = InitializeParameter[a] : &:r461_4 +# 461| r461_6(glval) = VariableAddress[b] : +# 461| mu461_7(bool) = InitializeParameter[b] : &:r461_6 # 462| r462_1(glval) = VariableAddress[x] : # 462| mu462_2(int) = Uninitialized[x] : &:r462_1 # 463| r463_1(glval) = VariableAddress[a] : -# 463| r463_2(bool) = Load : &:r463_1, ~mu461_4 +# 463| r463_2(bool) = Load : &:r463_1, ~m? # 463| v463_3(void) = ConditionalBranch : r463_2 #-----| False -> Block 1 #-----| True -> Block 2 @@ -2730,14 +2634,14 @@ ir.cpp: # 467| Block 2 # 467| r467_1(glval) = VariableAddress[a] : -# 467| r467_2(bool) = Load : &:r467_1, ~mu461_4 +# 467| r467_2(bool) = Load : &:r467_1, ~m? # 467| v467_3(void) = ConditionalBranch : r467_2 #-----| False -> Block 4 #-----| True -> Block 3 # 467| Block 3 # 467| r467_4(glval) = VariableAddress[b] : -# 467| r467_5(bool) = Load : &:r467_4, ~mu461_4 +# 467| r467_5(bool) = Load : &:r467_4, ~m? # 467| v467_6(void) = ConditionalBranch : r467_5 #-----| False -> Block 4 #-----| True -> Block 5 @@ -2756,32 +2660,30 @@ ir.cpp: # 473| Block 6 # 473| v473_1(void) = NoOp : -# 461| v461_9(void) = ReturnVoid : -# 461| v461_10(void) = UnmodeledUse : mu* -# 461| v461_11(void) = AliasedUse : ~mu461_4 -# 461| v461_12(void) = ExitFunction : +# 461| v461_8(void) = ReturnVoid : +# 461| v461_9(void) = AliasedUse : ~m? +# 461| v461_10(void) = ExitFunction : # 475| void ConditionValues(bool, bool) # 475| Block 0 # 475| v475_1(void) = EnterFunction : # 475| mu475_2(unknown) = AliasedDefinition : # 475| mu475_3(unknown) = InitializeNonLocal : -# 475| mu475_4(unknown) = UnmodeledDefinition : -# 475| r475_5(glval) = VariableAddress[a] : -# 475| mu475_6(bool) = InitializeParameter[a] : &:r475_5 -# 475| r475_7(glval) = VariableAddress[b] : -# 475| mu475_8(bool) = InitializeParameter[b] : &:r475_7 +# 475| r475_4(glval) = VariableAddress[a] : +# 475| mu475_5(bool) = InitializeParameter[a] : &:r475_4 +# 475| r475_6(glval) = VariableAddress[b] : +# 475| mu475_7(bool) = InitializeParameter[b] : &:r475_6 # 476| r476_1(glval) = VariableAddress[x] : # 476| mu476_2(bool) = Uninitialized[x] : &:r476_1 # 477| r477_1(glval) = VariableAddress[a] : -# 477| r477_2(bool) = Load : &:r477_1, ~mu475_4 +# 477| r477_2(bool) = Load : &:r477_1, ~m? # 477| v477_3(void) = ConditionalBranch : r477_2 #-----| False -> Block 10 #-----| True -> Block 1 # 477| Block 1 # 477| r477_4(glval) = VariableAddress[b] : -# 477| r477_5(bool) = Load : &:r477_4, ~mu475_4 +# 477| r477_5(bool) = Load : &:r477_4, ~m? # 477| v477_6(void) = ConditionalBranch : r477_5 #-----| False -> Block 10 #-----| True -> Block 12 @@ -2794,11 +2696,11 @@ ir.cpp: # 478| Block 3 # 478| r478_4(glval) = VariableAddress[#temp478:9] : -# 478| r478_5(bool) = Load : &:r478_4, ~mu475_4 +# 478| r478_5(bool) = Load : &:r478_4, ~m? # 478| r478_6(glval) = VariableAddress[x] : # 478| mu478_7(bool) = Store : &:r478_6, r478_5 # 479| r479_1(glval) = VariableAddress[a] : -# 479| r479_2(bool) = Load : &:r479_1, ~mu475_4 +# 479| r479_2(bool) = Load : &:r479_1, ~m? # 479| v479_3(void) = ConditionalBranch : r479_2 #-----| False -> Block 9 #-----| True -> Block 8 @@ -2811,7 +2713,7 @@ ir.cpp: # 478| Block 5 # 478| r478_11(glval) = VariableAddress[b] : -# 478| r478_12(bool) = Load : &:r478_11, ~mu475_4 +# 478| r478_12(bool) = Load : &:r478_11, ~m? # 478| v478_13(void) = ConditionalBranch : r478_12 #-----| False -> Block 2 #-----| True -> Block 4 @@ -2824,15 +2726,14 @@ ir.cpp: # 479| Block 7 # 479| r479_7(glval) = VariableAddress[#temp479:11] : -# 479| r479_8(bool) = Load : &:r479_7, ~mu475_4 +# 479| r479_8(bool) = Load : &:r479_7, ~m? # 479| r479_9(bool) = LogicalNot : r479_8 # 479| r479_10(glval) = VariableAddress[x] : # 479| mu479_11(bool) = Store : &:r479_10, r479_9 # 480| v480_1(void) = NoOp : -# 475| v475_9(void) = ReturnVoid : -# 475| v475_10(void) = UnmodeledUse : mu* -# 475| v475_11(void) = AliasedUse : ~mu475_4 -# 475| v475_12(void) = ExitFunction : +# 475| v475_8(void) = ReturnVoid : +# 475| v475_9(void) = AliasedUse : ~m? +# 475| v475_10(void) = ExitFunction : # 479| Block 8 # 479| r479_12(glval) = VariableAddress[#temp479:11] : @@ -2842,7 +2743,7 @@ ir.cpp: # 479| Block 9 # 479| r479_15(glval) = VariableAddress[b] : -# 479| r479_16(bool) = Load : &:r479_15, ~mu475_4 +# 479| r479_16(bool) = Load : &:r479_15, ~m? # 479| v479_17(void) = ConditionalBranch : r479_16 #-----| False -> Block 6 #-----| True -> Block 8 @@ -2855,11 +2756,11 @@ ir.cpp: # 477| Block 11 # 477| r477_10(glval) = VariableAddress[#temp477:9] : -# 477| r477_11(bool) = Load : &:r477_10, ~mu475_4 +# 477| r477_11(bool) = Load : &:r477_10, ~m? # 477| r477_12(glval) = VariableAddress[x] : # 477| mu477_13(bool) = Store : &:r477_12, r477_11 # 478| r478_14(glval) = VariableAddress[a] : -# 478| r478_15(bool) = Load : &:r478_14, ~mu475_4 +# 478| r478_15(bool) = Load : &:r478_14, ~m? # 478| v478_16(void) = ConditionalBranch : r478_15 #-----| False -> Block 5 #-----| True -> Block 4 @@ -2875,72 +2776,68 @@ ir.cpp: # 482| v482_1(void) = EnterFunction : # 482| mu482_2(unknown) = AliasedDefinition : # 482| mu482_3(unknown) = InitializeNonLocal : -# 482| mu482_4(unknown) = UnmodeledDefinition : -# 482| r482_5(glval) = VariableAddress[a] : -# 482| mu482_6(bool) = InitializeParameter[a] : &:r482_5 -# 482| r482_7(glval) = VariableAddress[x] : -# 482| mu482_8(int) = InitializeParameter[x] : &:r482_7 -# 482| r482_9(glval) = VariableAddress[y] : -# 482| mu482_10(int) = InitializeParameter[y] : &:r482_9 +# 482| r482_4(glval) = VariableAddress[a] : +# 482| mu482_5(bool) = InitializeParameter[a] : &:r482_4 +# 482| r482_6(glval) = VariableAddress[x] : +# 482| mu482_7(int) = InitializeParameter[x] : &:r482_6 +# 482| r482_8(glval) = VariableAddress[y] : +# 482| mu482_9(int) = InitializeParameter[y] : &:r482_8 # 483| r483_1(glval) = VariableAddress[z] : # 483| r483_2(glval) = VariableAddress[a] : -# 483| r483_3(bool) = Load : &:r483_2, ~mu482_4 +# 483| r483_3(bool) = Load : &:r483_2, ~m? # 483| v483_4(void) = ConditionalBranch : r483_3 #-----| False -> Block 2 #-----| True -> Block 1 # 483| Block 1 # 483| r483_5(glval) = VariableAddress[x] : -# 483| r483_6(int) = Load : &:r483_5, ~mu482_4 +# 483| r483_6(int) = Load : &:r483_5, ~m? # 483| r483_7(glval) = VariableAddress[#temp483:13] : # 483| mu483_8(int) = Store : &:r483_7, r483_6 #-----| Goto -> Block 3 # 483| Block 2 # 483| r483_9(glval) = VariableAddress[y] : -# 483| r483_10(int) = Load : &:r483_9, ~mu482_4 +# 483| r483_10(int) = Load : &:r483_9, ~m? # 483| r483_11(glval) = VariableAddress[#temp483:13] : # 483| mu483_12(int) = Store : &:r483_11, r483_10 #-----| Goto -> Block 3 # 483| Block 3 # 483| r483_13(glval) = VariableAddress[#temp483:13] : -# 483| r483_14(int) = Load : &:r483_13, ~mu482_4 +# 483| r483_14(int) = Load : &:r483_13, ~m? # 483| mu483_15(int) = Store : &:r483_1, r483_14 # 484| v484_1(void) = NoOp : -# 482| v482_11(void) = ReturnVoid : -# 482| v482_12(void) = UnmodeledUse : mu* -# 482| v482_13(void) = AliasedUse : ~mu482_4 -# 482| v482_14(void) = ExitFunction : +# 482| v482_10(void) = ReturnVoid : +# 482| v482_11(void) = AliasedUse : ~m? +# 482| v482_12(void) = ExitFunction : # 486| void Conditional_LValue(bool) # 486| Block 0 # 486| v486_1(void) = EnterFunction : # 486| mu486_2(unknown) = AliasedDefinition : # 486| mu486_3(unknown) = InitializeNonLocal : -# 486| mu486_4(unknown) = UnmodeledDefinition : -# 486| r486_5(glval) = VariableAddress[a] : -# 486| mu486_6(bool) = InitializeParameter[a] : &:r486_5 +# 486| r486_4(glval) = VariableAddress[a] : +# 486| mu486_5(bool) = InitializeParameter[a] : &:r486_4 # 487| r487_1(glval) = VariableAddress[x] : # 487| mu487_2(int) = Uninitialized[x] : &:r487_1 # 488| r488_1(glval) = VariableAddress[y] : # 488| mu488_2(int) = Uninitialized[y] : &:r488_1 # 489| r489_1(int) = Constant[5] : # 489| r489_2(glval) = VariableAddress[a] : -# 489| r489_3(bool) = Load : &:r489_2, ~mu486_4 +# 489| r489_3(bool) = Load : &:r489_2, ~m? # 489| v489_4(void) = ConditionalBranch : r489_3 #-----| False -> Block 3 #-----| True -> Block 2 # 489| Block 1 # 489| r489_5(glval) = VariableAddress[#temp489:6] : -# 489| r489_6(glval) = Load : &:r489_5, ~mu486_4 +# 489| r489_6(glval) = Load : &:r489_5, ~m? # 489| mu489_7(int) = Store : &:r489_6, r489_1 # 490| v490_1(void) = NoOp : -# 486| v486_7(void) = ReturnVoid : -# 486| v486_8(void) = UnmodeledUse : mu* -# 486| v486_9(void) = AliasedUse : ~mu486_4 -# 486| v486_10(void) = ExitFunction : +# 486| v486_6(void) = ReturnVoid : +# 486| v486_7(void) = AliasedUse : ~m? +# 486| v486_8(void) = ExitFunction : # 489| Block 2 # 489| r489_8(glval) = VariableAddress[x] : @@ -2959,11 +2856,10 @@ ir.cpp: # 492| v492_1(void) = EnterFunction : # 492| mu492_2(unknown) = AliasedDefinition : # 492| mu492_3(unknown) = InitializeNonLocal : -# 492| mu492_4(unknown) = UnmodeledDefinition : -# 492| r492_5(glval) = VariableAddress[a] : -# 492| mu492_6(bool) = InitializeParameter[a] : &:r492_5 +# 492| r492_4(glval) = VariableAddress[a] : +# 492| mu492_5(bool) = InitializeParameter[a] : &:r492_4 # 493| r493_1(glval) = VariableAddress[a] : -# 493| r493_2(bool) = Load : &:r493_1, ~mu492_4 +# 493| r493_2(bool) = Load : &:r493_1, ~m? # 493| v493_3(void) = ConditionalBranch : r493_2 #-----| False -> Block 1 #-----| True -> Block 3 @@ -2971,72 +2867,68 @@ ir.cpp: # 493| Block 1 # 493| r493_4(glval) = FunctionAddress[VoidFunc] : # 493| v493_5(void) = Call : func:r493_4 -# 493| mu493_6(unknown) = ^CallSideEffect : ~mu492_4 +# 493| mu493_6(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 2 # 494| Block 2 -# 494| v494_1(void) = NoOp : -# 492| v492_7(void) = ReturnVoid : -# 492| v492_8(void) = UnmodeledUse : mu* -# 492| v492_9(void) = AliasedUse : ~mu492_4 -# 492| v492_10(void) = ExitFunction : +# 494| v494_1(void) = NoOp : +# 492| v492_6(void) = ReturnVoid : +# 492| v492_7(void) = AliasedUse : ~m? +# 492| v492_8(void) = ExitFunction : # 493| Block 3 # 493| r493_7(glval) = FunctionAddress[VoidFunc] : # 493| v493_8(void) = Call : func:r493_7 -# 493| mu493_9(unknown) = ^CallSideEffect : ~mu492_4 +# 493| mu493_9(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 2 # 496| void Nullptr() # 496| Block 0 -# 496| v496_1(void) = EnterFunction : -# 496| mu496_2(unknown) = AliasedDefinition : -# 496| mu496_3(unknown) = InitializeNonLocal : -# 496| mu496_4(unknown) = UnmodeledDefinition : -# 497| r497_1(glval) = VariableAddress[p] : -# 497| r497_2(int *) = Constant[0] : -# 497| mu497_3(int *) = Store : &:r497_1, r497_2 -# 498| r498_1(glval) = VariableAddress[q] : -# 498| r498_2(int *) = Constant[0] : -# 498| mu498_3(int *) = Store : &:r498_1, r498_2 -# 499| r499_1(int *) = Constant[0] : -# 499| r499_2(glval) = VariableAddress[p] : -# 499| mu499_3(int *) = Store : &:r499_2, r499_1 -# 500| r500_1(int *) = Constant[0] : -# 500| r500_2(glval) = VariableAddress[q] : -# 500| mu500_3(int *) = Store : &:r500_2, r500_1 -# 501| v501_1(void) = NoOp : -# 496| v496_5(void) = ReturnVoid : -# 496| v496_6(void) = UnmodeledUse : mu* -# 496| v496_7(void) = AliasedUse : ~mu496_4 -# 496| v496_8(void) = ExitFunction : +# 496| v496_1(void) = EnterFunction : +# 496| mu496_2(unknown) = AliasedDefinition : +# 496| mu496_3(unknown) = InitializeNonLocal : +# 497| r497_1(glval) = VariableAddress[p] : +# 497| r497_2(int *) = Constant[0] : +# 497| mu497_3(int *) = Store : &:r497_1, r497_2 +# 498| r498_1(glval) = VariableAddress[q] : +# 498| r498_2(int *) = Constant[0] : +# 498| mu498_3(int *) = Store : &:r498_1, r498_2 +# 499| r499_1(int *) = Constant[0] : +# 499| r499_2(glval) = VariableAddress[p] : +# 499| mu499_3(int *) = Store : &:r499_2, r499_1 +# 500| r500_1(int *) = Constant[0] : +# 500| r500_2(glval) = VariableAddress[q] : +# 500| mu500_3(int *) = Store : &:r500_2, r500_1 +# 501| v501_1(void) = NoOp : +# 496| v496_4(void) = ReturnVoid : +# 496| v496_5(void) = AliasedUse : ~m? +# 496| v496_6(void) = ExitFunction : # 503| void InitList(int, float) # 503| Block 0 # 503| v503_1(void) = EnterFunction : # 503| mu503_2(unknown) = AliasedDefinition : # 503| mu503_3(unknown) = InitializeNonLocal : -# 503| mu503_4(unknown) = UnmodeledDefinition : -# 503| r503_5(glval) = VariableAddress[x] : -# 503| mu503_6(int) = InitializeParameter[x] : &:r503_5 -# 503| r503_7(glval) = VariableAddress[f] : -# 503| mu503_8(float) = InitializeParameter[f] : &:r503_7 +# 503| r503_4(glval) = VariableAddress[x] : +# 503| mu503_5(int) = InitializeParameter[x] : &:r503_4 +# 503| r503_6(glval) = VariableAddress[f] : +# 503| mu503_7(float) = InitializeParameter[f] : &:r503_6 # 504| r504_1(glval) = VariableAddress[pt1] : # 504| mu504_2(Point) = Uninitialized[pt1] : &:r504_1 # 504| r504_3(glval) = FieldAddress[x] : r504_1 # 504| r504_4(glval) = VariableAddress[x] : -# 504| r504_5(int) = Load : &:r504_4, ~mu503_4 +# 504| r504_5(int) = Load : &:r504_4, ~m? # 504| mu504_6(int) = Store : &:r504_3, r504_5 # 504| r504_7(glval) = FieldAddress[y] : r504_1 # 504| r504_8(glval) = VariableAddress[f] : -# 504| r504_9(float) = Load : &:r504_8, ~mu503_4 +# 504| r504_9(float) = Load : &:r504_8, ~m? # 504| r504_10(int) = Convert : r504_9 # 504| mu504_11(int) = Store : &:r504_7, r504_10 # 505| r505_1(glval) = VariableAddress[pt2] : # 505| mu505_2(Point) = Uninitialized[pt2] : &:r505_1 # 505| r505_3(glval) = FieldAddress[x] : r505_1 # 505| r505_4(glval) = VariableAddress[x] : -# 505| r505_5(int) = Load : &:r505_4, ~mu503_4 +# 505| r505_5(int) = Load : &:r505_4, ~m? # 505| mu505_6(int) = Store : &:r505_3, r505_5 # 505| r505_7(glval) = FieldAddress[y] : r505_1 # 505| r505_8(int) = Constant[0] : @@ -3056,21 +2948,19 @@ ir.cpp: # 509| r509_2(int) = Constant[0] : # 509| mu509_3(int) = Store : &:r509_1, r509_2 # 510| v510_1(void) = NoOp : -# 503| v503_9(void) = ReturnVoid : -# 503| v503_10(void) = UnmodeledUse : mu* -# 503| v503_11(void) = AliasedUse : ~mu503_4 -# 503| v503_12(void) = ExitFunction : +# 503| v503_8(void) = ReturnVoid : +# 503| v503_9(void) = AliasedUse : ~m? +# 503| v503_10(void) = ExitFunction : # 512| void NestedInitList(int, float) # 512| Block 0 # 512| v512_1(void) = EnterFunction : # 512| mu512_2(unknown) = AliasedDefinition : # 512| mu512_3(unknown) = InitializeNonLocal : -# 512| mu512_4(unknown) = UnmodeledDefinition : -# 512| r512_5(glval) = VariableAddress[x] : -# 512| mu512_6(int) = InitializeParameter[x] : &:r512_5 -# 512| r512_7(glval) = VariableAddress[f] : -# 512| mu512_8(float) = InitializeParameter[f] : &:r512_7 +# 512| r512_4(glval) = VariableAddress[x] : +# 512| mu512_5(int) = InitializeParameter[x] : &:r512_4 +# 512| r512_6(glval) = VariableAddress[f] : +# 512| mu512_7(float) = InitializeParameter[f] : &:r512_6 # 513| r513_1(glval) = VariableAddress[r1] : # 513| mu513_2(Rect) = Uninitialized[r1] : &:r513_1 # 513| r513_3(glval) = FieldAddress[topLeft] : r513_1 @@ -3084,11 +2974,11 @@ ir.cpp: # 514| r514_3(glval) = FieldAddress[topLeft] : r514_1 # 514| r514_4(glval) = FieldAddress[x] : r514_3 # 514| r514_5(glval) = VariableAddress[x] : -# 514| r514_6(int) = Load : &:r514_5, ~mu512_4 +# 514| r514_6(int) = Load : &:r514_5, ~m? # 514| mu514_7(int) = Store : &:r514_4, r514_6 # 514| r514_8(glval) = FieldAddress[y] : r514_3 # 514| r514_9(glval) = VariableAddress[f] : -# 514| r514_10(float) = Load : &:r514_9, ~mu512_4 +# 514| r514_10(float) = Load : &:r514_9, ~m? # 514| r514_11(int) = Convert : r514_10 # 514| mu514_12(int) = Store : &:r514_8, r514_11 # 514| r514_13(glval) = FieldAddress[bottomRight] : r514_1 @@ -3099,21 +2989,21 @@ ir.cpp: # 515| r515_3(glval) = FieldAddress[topLeft] : r515_1 # 515| r515_4(glval) = FieldAddress[x] : r515_3 # 515| r515_5(glval) = VariableAddress[x] : -# 515| r515_6(int) = Load : &:r515_5, ~mu512_4 +# 515| r515_6(int) = Load : &:r515_5, ~m? # 515| mu515_7(int) = Store : &:r515_4, r515_6 # 515| r515_8(glval) = FieldAddress[y] : r515_3 # 515| r515_9(glval) = VariableAddress[f] : -# 515| r515_10(float) = Load : &:r515_9, ~mu512_4 +# 515| r515_10(float) = Load : &:r515_9, ~m? # 515| r515_11(int) = Convert : r515_10 # 515| mu515_12(int) = Store : &:r515_8, r515_11 # 515| r515_13(glval) = FieldAddress[bottomRight] : r515_1 # 515| r515_14(glval) = FieldAddress[x] : r515_13 # 515| r515_15(glval) = VariableAddress[x] : -# 515| r515_16(int) = Load : &:r515_15, ~mu512_4 +# 515| r515_16(int) = Load : &:r515_15, ~m? # 515| mu515_17(int) = Store : &:r515_14, r515_16 # 515| r515_18(glval) = FieldAddress[y] : r515_13 # 515| r515_19(glval) = VariableAddress[f] : -# 515| r515_20(float) = Load : &:r515_19, ~mu512_4 +# 515| r515_20(float) = Load : &:r515_19, ~m? # 515| r515_21(int) = Convert : r515_20 # 515| mu515_22(int) = Store : &:r515_18, r515_21 # 516| r516_1(glval) = VariableAddress[r4] : @@ -3121,7 +3011,7 @@ ir.cpp: # 516| r516_3(glval) = FieldAddress[topLeft] : r516_1 # 516| r516_4(glval) = FieldAddress[x] : r516_3 # 516| r516_5(glval) = VariableAddress[x] : -# 516| r516_6(int) = Load : &:r516_5, ~mu512_4 +# 516| r516_6(int) = Load : &:r516_5, ~m? # 516| mu516_7(int) = Store : &:r516_4, r516_6 # 516| r516_8(glval) = FieldAddress[y] : r516_3 # 516| r516_9(int) = Constant[0] : @@ -3129,27 +3019,25 @@ ir.cpp: # 516| r516_11(glval) = FieldAddress[bottomRight] : r516_1 # 516| r516_12(glval) = FieldAddress[x] : r516_11 # 516| r516_13(glval) = VariableAddress[x] : -# 516| r516_14(int) = Load : &:r516_13, ~mu512_4 +# 516| r516_14(int) = Load : &:r516_13, ~m? # 516| mu516_15(int) = Store : &:r516_12, r516_14 # 516| r516_16(glval) = FieldAddress[y] : r516_11 # 516| r516_17(int) = Constant[0] : # 516| mu516_18(int) = Store : &:r516_16, r516_17 # 517| v517_1(void) = NoOp : -# 512| v512_9(void) = ReturnVoid : -# 512| v512_10(void) = UnmodeledUse : mu* -# 512| v512_11(void) = AliasedUse : ~mu512_4 -# 512| v512_12(void) = ExitFunction : +# 512| v512_8(void) = ReturnVoid : +# 512| v512_9(void) = AliasedUse : ~m? +# 512| v512_10(void) = ExitFunction : # 519| void ArrayInit(int, float) # 519| Block 0 # 519| v519_1(void) = EnterFunction : # 519| mu519_2(unknown) = AliasedDefinition : # 519| mu519_3(unknown) = InitializeNonLocal : -# 519| mu519_4(unknown) = UnmodeledDefinition : -# 519| r519_5(glval) = VariableAddress[x] : -# 519| mu519_6(int) = InitializeParameter[x] : &:r519_5 -# 519| r519_7(glval) = VariableAddress[f] : -# 519| mu519_8(float) = InitializeParameter[f] : &:r519_7 +# 519| r519_4(glval) = VariableAddress[x] : +# 519| mu519_5(int) = InitializeParameter[x] : &:r519_4 +# 519| r519_6(glval) = VariableAddress[f] : +# 519| mu519_7(float) = InitializeParameter[f] : &:r519_6 # 520| r520_1(glval) = VariableAddress[a1] : # 520| mu520_2(int[3]) = Uninitialized[a1] : &:r520_1 # 520| r520_3(int) = Constant[0] : @@ -3161,12 +3049,12 @@ ir.cpp: # 521| r521_3(int) = Constant[0] : # 521| r521_4(glval) = PointerAdd[4] : r521_1, r521_3 # 521| r521_5(glval) = VariableAddress[x] : -# 521| r521_6(int) = Load : &:r521_5, ~mu519_4 +# 521| r521_6(int) = Load : &:r521_5, ~m? # 521| mu521_7(int) = Store : &:r521_4, r521_6 # 521| r521_8(int) = Constant[1] : # 521| r521_9(glval) = PointerAdd[4] : r521_1, r521_8 # 521| r521_10(glval) = VariableAddress[f] : -# 521| r521_11(float) = Load : &:r521_10, ~mu519_4 +# 521| r521_11(float) = Load : &:r521_10, ~m? # 521| r521_12(int) = Convert : r521_11 # 521| mu521_13(int) = Store : &:r521_9, r521_12 # 521| r521_14(int) = Constant[2] : @@ -3178,65 +3066,60 @@ ir.cpp: # 522| r522_3(int) = Constant[0] : # 522| r522_4(glval) = PointerAdd[4] : r522_1, r522_3 # 522| r522_5(glval) = VariableAddress[x] : -# 522| r522_6(int) = Load : &:r522_5, ~mu519_4 +# 522| r522_6(int) = Load : &:r522_5, ~m? # 522| mu522_7(int) = Store : &:r522_4, r522_6 # 522| r522_8(int) = Constant[1] : # 522| r522_9(glval) = PointerAdd[4] : r522_1, r522_8 # 522| r522_10(unknown[8]) = Constant[0] : # 522| mu522_11(unknown[8]) = Store : &:r522_9, r522_10 # 523| v523_1(void) = NoOp : -# 519| v519_9(void) = ReturnVoid : -# 519| v519_10(void) = UnmodeledUse : mu* -# 519| v519_11(void) = AliasedUse : ~mu519_4 -# 519| v519_12(void) = ExitFunction : +# 519| v519_8(void) = ReturnVoid : +# 519| v519_9(void) = AliasedUse : ~m? +# 519| v519_10(void) = ExitFunction : # 530| void UnionInit(int, float) # 530| Block 0 # 530| v530_1(void) = EnterFunction : # 530| mu530_2(unknown) = AliasedDefinition : # 530| mu530_3(unknown) = InitializeNonLocal : -# 530| mu530_4(unknown) = UnmodeledDefinition : -# 530| r530_5(glval) = VariableAddress[x] : -# 530| mu530_6(int) = InitializeParameter[x] : &:r530_5 -# 530| r530_7(glval) = VariableAddress[f] : -# 530| mu530_8(float) = InitializeParameter[f] : &:r530_7 +# 530| r530_4(glval) = VariableAddress[x] : +# 530| mu530_5(int) = InitializeParameter[x] : &:r530_4 +# 530| r530_6(glval) = VariableAddress[f] : +# 530| mu530_7(float) = InitializeParameter[f] : &:r530_6 # 531| r531_1(glval) = VariableAddress[u1] : # 531| mu531_2(U) = Uninitialized[u1] : &:r531_1 # 531| r531_3(glval) = FieldAddress[d] : r531_1 # 531| r531_4(glval) = VariableAddress[f] : -# 531| r531_5(float) = Load : &:r531_4, ~mu530_4 +# 531| r531_5(float) = Load : &:r531_4, ~m? # 531| r531_6(double) = Convert : r531_5 # 531| mu531_7(double) = Store : &:r531_3, r531_6 # 533| v533_1(void) = NoOp : -# 530| v530_9(void) = ReturnVoid : -# 530| v530_10(void) = UnmodeledUse : mu* -# 530| v530_11(void) = AliasedUse : ~mu530_4 -# 530| v530_12(void) = ExitFunction : +# 530| v530_8(void) = ReturnVoid : +# 530| v530_9(void) = AliasedUse : ~m? +# 530| v530_10(void) = ExitFunction : # 535| void EarlyReturn(int, int) # 535| Block 0 # 535| v535_1(void) = EnterFunction : # 535| mu535_2(unknown) = AliasedDefinition : # 535| mu535_3(unknown) = InitializeNonLocal : -# 535| mu535_4(unknown) = UnmodeledDefinition : -# 535| r535_5(glval) = VariableAddress[x] : -# 535| mu535_6(int) = InitializeParameter[x] : &:r535_5 -# 535| r535_7(glval) = VariableAddress[y] : -# 535| mu535_8(int) = InitializeParameter[y] : &:r535_7 +# 535| r535_4(glval) = VariableAddress[x] : +# 535| mu535_5(int) = InitializeParameter[x] : &:r535_4 +# 535| r535_6(glval) = VariableAddress[y] : +# 535| mu535_7(int) = InitializeParameter[y] : &:r535_6 # 536| r536_1(glval) = VariableAddress[x] : -# 536| r536_2(int) = Load : &:r536_1, ~mu535_4 +# 536| r536_2(int) = Load : &:r536_1, ~m? # 536| r536_3(glval) = VariableAddress[y] : -# 536| r536_4(int) = Load : &:r536_3, ~mu535_4 +# 536| r536_4(int) = Load : &:r536_3, ~m? # 536| r536_5(bool) = CompareLT : r536_2, r536_4 # 536| v536_6(void) = ConditionalBranch : r536_5 #-----| False -> Block 3 #-----| True -> Block 2 # 535| Block 1 -# 535| v535_9(void) = ReturnVoid : -# 535| v535_10(void) = UnmodeledUse : mu* -# 535| v535_11(void) = AliasedUse : ~mu535_4 -# 535| v535_12(void) = ExitFunction : +# 535| v535_8(void) = ReturnVoid : +# 535| v535_9(void) = AliasedUse : ~m? +# 535| v535_10(void) = ExitFunction : # 537| Block 2 # 537| v537_1(void) = NoOp : @@ -3244,7 +3127,7 @@ ir.cpp: # 540| Block 3 # 540| r540_1(glval) = VariableAddress[x] : -# 540| r540_2(int) = Load : &:r540_1, ~mu535_4 +# 540| r540_2(int) = Load : &:r540_1, ~m? # 540| r540_3(glval) = VariableAddress[y] : # 540| mu540_4(int) = Store : &:r540_3, r540_2 # 541| v541_1(void) = NoOp : @@ -3255,40 +3138,38 @@ ir.cpp: # 543| v543_1(void) = EnterFunction : # 543| mu543_2(unknown) = AliasedDefinition : # 543| mu543_3(unknown) = InitializeNonLocal : -# 543| mu543_4(unknown) = UnmodeledDefinition : -# 543| r543_5(glval) = VariableAddress[x] : -# 543| mu543_6(int) = InitializeParameter[x] : &:r543_5 -# 543| r543_7(glval) = VariableAddress[y] : -# 543| mu543_8(int) = InitializeParameter[y] : &:r543_7 +# 543| r543_4(glval) = VariableAddress[x] : +# 543| mu543_5(int) = InitializeParameter[x] : &:r543_4 +# 543| r543_6(glval) = VariableAddress[y] : +# 543| mu543_7(int) = InitializeParameter[y] : &:r543_6 # 544| r544_1(glval) = VariableAddress[x] : -# 544| r544_2(int) = Load : &:r544_1, ~mu543_4 +# 544| r544_2(int) = Load : &:r544_1, ~m? # 544| r544_3(glval) = VariableAddress[y] : -# 544| r544_4(int) = Load : &:r544_3, ~mu543_4 +# 544| r544_4(int) = Load : &:r544_3, ~m? # 544| r544_5(bool) = CompareLT : r544_2, r544_4 # 544| v544_6(void) = ConditionalBranch : r544_5 #-----| False -> Block 3 #-----| True -> Block 2 # 543| Block 1 -# 543| r543_9(glval) = VariableAddress[#return] : -# 543| v543_10(void) = ReturnValue : &:r543_9, ~mu543_4 -# 543| v543_11(void) = UnmodeledUse : mu* -# 543| v543_12(void) = AliasedUse : ~mu543_4 -# 543| v543_13(void) = ExitFunction : +# 543| r543_8(glval) = VariableAddress[#return] : +# 543| v543_9(void) = ReturnValue : &:r543_8, ~m? +# 543| v543_10(void) = AliasedUse : ~m? +# 543| v543_11(void) = ExitFunction : # 545| Block 2 # 545| r545_1(glval) = VariableAddress[#return] : # 545| r545_2(glval) = VariableAddress[x] : -# 545| r545_3(int) = Load : &:r545_2, ~mu543_4 +# 545| r545_3(int) = Load : &:r545_2, ~m? # 545| mu545_4(int) = Store : &:r545_1, r545_3 #-----| Goto -> Block 1 # 548| Block 3 # 548| r548_1(glval) = VariableAddress[#return] : # 548| r548_2(glval) = VariableAddress[x] : -# 548| r548_3(int) = Load : &:r548_2, ~mu543_4 +# 548| r548_3(int) = Load : &:r548_2, ~m? # 548| r548_4(glval) = VariableAddress[y] : -# 548| r548_5(int) = Load : &:r548_4, ~mu543_4 +# 548| r548_5(int) = Load : &:r548_4, ~m? # 548| r548_6(int) = Add : r548_3, r548_5 # 548| mu548_7(int) = Store : &:r548_1, r548_6 #-----| Goto -> Block 1 @@ -3298,32 +3179,29 @@ ir.cpp: # 551| v551_1(void) = EnterFunction : # 551| mu551_2(unknown) = AliasedDefinition : # 551| mu551_3(unknown) = InitializeNonLocal : -# 551| mu551_4(unknown) = UnmodeledDefinition : -# 551| r551_5(glval<..(*)(..)>) = VariableAddress[pfn] : -# 551| mu551_6(..(*)(..)) = InitializeParameter[pfn] : &:r551_5 +# 551| r551_4(glval<..(*)(..)>) = VariableAddress[pfn] : +# 551| mu551_5(..(*)(..)) = InitializeParameter[pfn] : &:r551_4 # 552| r552_1(glval) = VariableAddress[#return] : # 552| r552_2(glval<..(*)(..)>) = VariableAddress[pfn] : -# 552| r552_3(..(*)(..)) = Load : &:r552_2, ~mu551_4 +# 552| r552_3(..(*)(..)) = Load : &:r552_2, ~m? # 552| r552_4(int) = Constant[5] : # 552| r552_5(int) = Call : func:r552_3, 0:r552_4 -# 552| mu552_6(unknown) = ^CallSideEffect : ~mu551_4 +# 552| mu552_6(unknown) = ^CallSideEffect : ~m? # 552| mu552_7(int) = Store : &:r552_1, r552_5 -# 551| r551_7(glval) = VariableAddress[#return] : -# 551| v551_8(void) = ReturnValue : &:r551_7, ~mu551_4 -# 551| v551_9(void) = UnmodeledUse : mu* -# 551| v551_10(void) = AliasedUse : ~mu551_4 -# 551| v551_11(void) = ExitFunction : +# 551| r551_6(glval) = VariableAddress[#return] : +# 551| v551_7(void) = ReturnValue : &:r551_6, ~m? +# 551| v551_8(void) = AliasedUse : ~m? +# 551| v551_9(void) = ExitFunction : # 560| int EnumSwitch(E) # 560| Block 0 # 560| v560_1(void) = EnterFunction : # 560| mu560_2(unknown) = AliasedDefinition : # 560| mu560_3(unknown) = InitializeNonLocal : -# 560| mu560_4(unknown) = UnmodeledDefinition : -# 560| r560_5(glval) = VariableAddress[e] : -# 560| mu560_6(E) = InitializeParameter[e] : &:r560_5 +# 560| r560_4(glval) = VariableAddress[e] : +# 560| mu560_5(E) = InitializeParameter[e] : &:r560_4 # 561| r561_1(glval) = VariableAddress[e] : -# 561| r561_2(E) = Load : &:r561_1, ~mu560_4 +# 561| r561_2(E) = Load : &:r561_1, ~m? # 561| r561_3(int) = Convert : r561_2 # 561| v561_4(void) = Switch : r561_3 #-----| Case[0] -> Block 4 @@ -3331,11 +3209,10 @@ ir.cpp: #-----| Default -> Block 3 # 560| Block 1 -# 560| r560_7(glval) = VariableAddress[#return] : -# 560| v560_8(void) = ReturnValue : &:r560_7, ~mu560_4 -# 560| v560_9(void) = UnmodeledUse : mu* -# 560| v560_10(void) = AliasedUse : ~mu560_4 -# 560| v560_11(void) = ExitFunction : +# 560| r560_6(glval) = VariableAddress[#return] : +# 560| v560_7(void) = ReturnValue : &:r560_6, ~m? +# 560| v560_8(void) = AliasedUse : ~m? +# 560| v560_9(void) = ExitFunction : # 564| Block 2 # 564| v564_1(void) = NoOp : @@ -3363,18 +3240,17 @@ ir.cpp: # 571| v571_1(void) = EnterFunction : # 571| mu571_2(unknown) = AliasedDefinition : # 571| mu571_3(unknown) = InitializeNonLocal : -# 571| mu571_4(unknown) = UnmodeledDefinition : # 572| r572_1(glval) = VariableAddress[a_pad] : # 572| r572_2(glval) = StringConstant[""] : -# 572| r572_3(char[32]) = Load : &:r572_2, ~mu571_4 +# 572| r572_3(char[32]) = Load : &:r572_2, ~m? # 572| mu572_4(char[32]) = Store : &:r572_1, r572_3 # 573| r573_1(glval) = VariableAddress[a_nopad] : # 573| r573_2(glval) = StringConstant["foo"] : -# 573| r573_3(char[4]) = Load : &:r573_2, ~mu571_4 +# 573| r573_3(char[4]) = Load : &:r573_2, ~m? # 573| mu573_4(char[4]) = Store : &:r573_1, r573_3 # 574| r574_1(glval) = VariableAddress[a_infer] : # 574| r574_2(glval) = StringConstant["blah"] : -# 574| r574_3(char[5]) = Load : &:r574_2, ~mu571_4 +# 574| r574_3(char[5]) = Load : &:r574_2, ~m? # 574| mu574_4(char[5]) = Store : &:r574_1, r574_3 # 575| r575_1(glval) = VariableAddress[b] : # 575| mu575_2(char[2]) = Uninitialized[b] : &:r575_1 @@ -3415,17 +3291,15 @@ ir.cpp: # 579| r579_9(unknown[2]) = Constant[0] : # 579| mu579_10(unknown[2]) = Store : &:r579_8, r579_9 # 580| v580_1(void) = NoOp : -# 571| v571_5(void) = ReturnVoid : -# 571| v571_6(void) = UnmodeledUse : mu* -# 571| v571_7(void) = AliasedUse : ~mu571_4 -# 571| v571_8(void) = ExitFunction : +# 571| v571_4(void) = ReturnVoid : +# 571| v571_5(void) = AliasedUse : ~m? +# 571| v571_6(void) = ExitFunction : # 584| void VarArgs() # 584| Block 0 # 584| v584_1(void) = EnterFunction : # 584| mu584_2(unknown) = AliasedDefinition : # 584| mu584_3(unknown) = InitializeNonLocal : -# 584| mu584_4(unknown) = UnmodeledDefinition : # 585| r585_1(glval) = FunctionAddress[VarArgFunction] : # 585| r585_2(glval) = StringConstant["%d %s"] : # 585| r585_3(char *) = Convert : r585_2 @@ -3433,23 +3307,21 @@ ir.cpp: # 585| r585_5(glval) = StringConstant["string"] : # 585| r585_6(char *) = Convert : r585_5 # 585| v585_7(void) = Call : func:r585_1, 0:r585_3, 1:r585_4, 2:r585_6 -# 585| mu585_8(unknown) = ^CallSideEffect : ~mu584_4 -# 585| v585_9(void) = ^BufferReadSideEffect[0] : &:r585_3, ~mu584_4 -# 585| v585_10(void) = ^BufferReadSideEffect[2] : &:r585_6, ~mu584_4 +# 585| mu585_8(unknown) = ^CallSideEffect : ~m? +# 585| v585_9(void) = ^BufferReadSideEffect[0] : &:r585_3, ~m? +# 585| v585_10(void) = ^BufferReadSideEffect[2] : &:r585_6, ~m? # 585| mu585_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r585_3 # 585| mu585_12(unknown) = ^BufferMayWriteSideEffect[2] : &:r585_6 # 586| v586_1(void) = NoOp : -# 584| v584_5(void) = ReturnVoid : -# 584| v584_6(void) = UnmodeledUse : mu* -# 584| v584_7(void) = AliasedUse : ~mu584_4 -# 584| v584_8(void) = ExitFunction : +# 584| v584_4(void) = ReturnVoid : +# 584| v584_5(void) = AliasedUse : ~m? +# 584| v584_6(void) = ExitFunction : # 590| void SetFuncPtr() # 590| Block 0 # 590| v590_1(void) = EnterFunction : # 590| mu590_2(unknown) = AliasedDefinition : # 590| mu590_3(unknown) = InitializeNonLocal : -# 590| mu590_4(unknown) = UnmodeledDefinition : # 591| r591_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 591| r591_2(..(*)(..)) = FunctionAddress[FuncPtrTarget] : # 591| mu591_3(..(*)(..)) = Store : &:r591_1, r591_2 @@ -3469,22 +3341,20 @@ ir.cpp: # 594| r594_6(glval<..(*)(..)>) = VariableAddress[pfn] : # 594| mu594_7(..(*)(..)) = Store : &:r594_6, r594_5 # 595| v595_1(void) = NoOp : -# 590| v590_5(void) = ReturnVoid : -# 590| v590_6(void) = UnmodeledUse : mu* -# 590| v590_7(void) = AliasedUse : ~mu590_4 -# 590| v590_8(void) = ExitFunction : +# 590| v590_4(void) = ReturnVoid : +# 590| v590_5(void) = AliasedUse : ~m? +# 590| v590_6(void) = ExitFunction : # 615| void DeclareObject() # 615| Block 0 # 615| v615_1(void) = EnterFunction : # 615| mu615_2(unknown) = AliasedDefinition : # 615| mu615_3(unknown) = InitializeNonLocal : -# 615| mu615_4(unknown) = UnmodeledDefinition : # 616| r616_1(glval) = VariableAddress[s1] : # 616| mu616_2(String) = Uninitialized[s1] : &:r616_1 # 616| r616_3(glval) = FunctionAddress[String] : # 616| v616_4(void) = Call : func:r616_3, this:r616_1 -# 616| mu616_5(unknown) = ^CallSideEffect : ~mu615_4 +# 616| mu616_5(unknown) = ^CallSideEffect : ~m? # 616| mu616_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r616_1 # 617| r617_1(glval) = VariableAddress[s2] : # 617| mu617_2(String) = Uninitialized[s2] : &:r617_1 @@ -3492,14 +3362,14 @@ ir.cpp: # 617| r617_4(glval) = StringConstant["hello"] : # 617| r617_5(char *) = Convert : r617_4 # 617| v617_6(void) = Call : func:r617_3, this:r617_1, 0:r617_5 -# 617| mu617_7(unknown) = ^CallSideEffect : ~mu615_4 +# 617| mu617_7(unknown) = ^CallSideEffect : ~m? # 617| mu617_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r617_1 -# 617| v617_9(void) = ^BufferReadSideEffect[0] : &:r617_5, ~mu615_4 +# 617| v617_9(void) = ^BufferReadSideEffect[0] : &:r617_5, ~m? # 617| mu617_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r617_5 # 618| r618_1(glval) = VariableAddress[s3] : # 618| r618_2(glval) = FunctionAddress[ReturnObject] : # 618| r618_3(String) = Call : func:r618_2 -# 618| mu618_4(unknown) = ^CallSideEffect : ~mu615_4 +# 618| mu618_4(unknown) = ^CallSideEffect : ~m? # 618| mu618_5(String) = Store : &:r618_1, r618_3 # 619| r619_1(glval) = VariableAddress[s4] : # 619| mu619_2(String) = Uninitialized[s4] : &:r619_1 @@ -3507,332 +3377,341 @@ ir.cpp: # 619| r619_4(glval) = StringConstant["test"] : # 619| r619_5(char *) = Convert : r619_4 # 619| v619_6(void) = Call : func:r619_3, this:r619_1, 0:r619_5 -# 619| mu619_7(unknown) = ^CallSideEffect : ~mu615_4 +# 619| mu619_7(unknown) = ^CallSideEffect : ~m? # 619| mu619_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r619_1 -# 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~mu615_4 +# 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~m? # 619| mu619_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r619_5 # 620| v620_1(void) = NoOp : -# 615| v615_5(void) = ReturnVoid : -# 615| v615_6(void) = UnmodeledUse : mu* -# 615| v615_7(void) = AliasedUse : ~mu615_4 -# 615| v615_8(void) = ExitFunction : +# 615| v615_4(void) = ReturnVoid : +# 615| v615_5(void) = AliasedUse : ~m? +# 615| v615_6(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 # 622| v622_1(void) = EnterFunction : # 622| mu622_2(unknown) = AliasedDefinition : # 622| mu622_3(unknown) = InitializeNonLocal : -# 622| mu622_4(unknown) = UnmodeledDefinition : -# 622| r622_5(glval) = VariableAddress[r] : -# 622| mu622_6(String &) = InitializeParameter[r] : &:r622_5 -# 622| r622_7(String &) = Load : &:r622_5, ~mu622_4 -# 622| mu622_8(unknown) = InitializeIndirection[r] : &:r622_7 -# 622| r622_9(glval) = VariableAddress[p] : -# 622| mu622_10(String *) = InitializeParameter[p] : &:r622_9 -# 622| r622_11(String *) = Load : &:r622_9, ~mu622_4 -# 622| mu622_12(unknown) = InitializeIndirection[p] : &:r622_11 -# 622| r622_13(glval) = VariableAddress[s] : -# 622| mu622_14(String) = InitializeParameter[s] : &:r622_13 +# 622| r622_4(glval) = VariableAddress[r] : +# 622| mu622_5(String &) = InitializeParameter[r] : &:r622_4 +# 622| r622_6(String &) = Load : &:r622_4, ~m? +# 622| mu622_7(unknown) = InitializeIndirection[r] : &:r622_6 +# 622| r622_8(glval) = VariableAddress[p] : +# 622| mu622_9(String *) = InitializeParameter[p] : &:r622_8 +# 622| r622_10(String *) = Load : &:r622_8, ~m? +# 622| mu622_11(unknown) = InitializeIndirection[p] : &:r622_10 +# 622| r622_12(glval) = VariableAddress[s] : +# 622| mu622_13(String) = InitializeParameter[s] : &:r622_12 # 623| r623_1(glval) = VariableAddress[r] : -# 623| r623_2(String &) = Load : &:r623_1, ~mu622_4 +# 623| r623_2(String &) = Load : &:r623_1, ~m? # 623| r623_3(glval) = CopyValue : r623_2 # 623| r623_4(glval) = Convert : r623_3 # 623| r623_5(glval) = FunctionAddress[c_str] : # 623| r623_6(char *) = Call : func:r623_5, this:r623_4 -# 623| mu623_7(unknown) = ^CallSideEffect : ~mu622_4 -# 623| v623_8(void) = ^BufferReadSideEffect[-1] : &:r623_4, ~mu622_4 +# 623| mu623_7(unknown) = ^CallSideEffect : ~m? +# 623| v623_8(void) = ^BufferReadSideEffect[-1] : &:r623_4, ~m? # 623| mu623_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r623_4 # 624| r624_1(glval) = VariableAddress[p] : -# 624| r624_2(String *) = Load : &:r624_1, ~mu622_4 +# 624| r624_2(String *) = Load : &:r624_1, ~m? # 624| r624_3(String *) = Convert : r624_2 # 624| r624_4(glval) = FunctionAddress[c_str] : # 624| r624_5(char *) = Call : func:r624_4, this:r624_3 -# 624| mu624_6(unknown) = ^CallSideEffect : ~mu622_4 -# 624| v624_7(void) = ^BufferReadSideEffect[-1] : &:r624_3, ~mu622_4 +# 624| mu624_6(unknown) = ^CallSideEffect : ~m? +# 624| v624_7(void) = ^BufferReadSideEffect[-1] : &:r624_3, ~m? # 624| mu624_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r624_3 # 625| r625_1(glval) = VariableAddress[s] : # 625| r625_2(glval) = Convert : r625_1 # 625| r625_3(glval) = FunctionAddress[c_str] : # 625| r625_4(char *) = Call : func:r625_3, this:r625_2 -# 625| mu625_5(unknown) = ^CallSideEffect : ~mu622_4 -# 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~mu622_4 +# 625| mu625_5(unknown) = ^CallSideEffect : ~m? +# 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~m? # 625| mu625_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r625_2 # 626| v626_1(void) = NoOp : -# 622| v622_15(void) = ReturnIndirection[r] : &:r622_7, ~mu622_4 -# 622| v622_16(void) = ReturnIndirection[p] : &:r622_11, ~mu622_4 -# 622| v622_17(void) = ReturnVoid : -# 622| v622_18(void) = UnmodeledUse : mu* -# 622| v622_19(void) = AliasedUse : ~mu622_4 -# 622| v622_20(void) = ExitFunction : +# 622| v622_14(void) = ReturnIndirection[r] : &:r622_6, ~m? +# 622| v622_15(void) = ReturnIndirection[p] : &:r622_10, ~m? +# 622| v622_16(void) = ReturnVoid : +# 622| v622_17(void) = AliasedUse : ~m? +# 622| v622_18(void) = ExitFunction : # 628| void C::~C() # 628| Block 0 -# 628| v628_1(void) = EnterFunction : -# 628| mu628_2(unknown) = AliasedDefinition : -# 628| mu628_3(unknown) = InitializeNonLocal : -# 628| mu628_4(unknown) = UnmodeledDefinition : -# 628| r628_5(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 628| r628_6(glval) = FieldAddress[m_f] : r628_5 -# 628| r628_7(glval) = FunctionAddress[~String] : -# 628| v628_8(void) = Call : func:r628_7, this:r628_6 -# 628| mu628_9(unknown) = ^CallSideEffect : ~mu628_4 -# 628| r628_10(glval) = FieldAddress[m_b] : r628_5 -# 628| r628_11(glval) = FunctionAddress[~String] : -# 628| v628_12(void) = Call : func:r628_11, this:r628_10 -# 628| mu628_13(unknown) = ^CallSideEffect : ~mu628_4 -# 628| v628_14(void) = ReturnVoid : -# 628| v628_15(void) = UnmodeledUse : mu* -# 628| v628_16(void) = AliasedUse : ~mu628_4 -# 628| v628_17(void) = ExitFunction : +# 628| v628_1(void) = EnterFunction : +# 628| mu628_2(unknown) = AliasedDefinition : +# 628| mu628_3(unknown) = InitializeNonLocal : +# 628| r628_4(glval) = VariableAddress[#this] : +# 628| mu628_5(glval) = InitializeParameter[#this] : &:r628_4 +# 628| r628_6(glval) = Load : &:r628_4, ~m? +# 628| mu628_7(C) = InitializeIndirection[#this] : &:r628_6 +#-----| v0_1(void) = NoOp : +# 628| r628_8(glval) = FieldAddress[m_f] : mu628_5 +# 628| r628_9(glval) = FunctionAddress[~String] : +# 628| v628_10(void) = Call : func:r628_9, this:r628_8 +# 628| mu628_11(unknown) = ^CallSideEffect : ~m? +# 628| r628_12(glval) = FieldAddress[m_b] : mu628_5 +# 628| r628_13(glval) = FunctionAddress[~String] : +# 628| v628_14(void) = Call : func:r628_13, this:r628_12 +# 628| mu628_15(unknown) = ^CallSideEffect : ~m? +# 628| v628_16(void) = ReturnIndirection[#this] : &:r628_6, ~m? +# 628| v628_17(void) = ReturnVoid : +# 628| v628_18(void) = AliasedUse : ~m? +# 628| v628_19(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 # 630| v630_1(void) = EnterFunction : # 630| mu630_2(unknown) = AliasedDefinition : # 630| mu630_3(unknown) = InitializeNonLocal : -# 630| mu630_4(unknown) = UnmodeledDefinition : -# 630| r630_5(glval) = VariableAddress[x] : -# 630| mu630_6(int) = InitializeParameter[x] : &:r630_5 +# 630| r630_4(glval) = VariableAddress[x] : +# 630| mu630_5(int) = InitializeParameter[x] : &:r630_4 # 631| r631_1(glval) = VariableAddress[#return] : # 631| r631_2(glval) = VariableAddress[x] : -# 631| r631_3(int) = Load : &:r631_2, ~mu630_4 +# 631| r631_3(int) = Load : &:r631_2, ~m? # 631| mu631_4(int) = Store : &:r631_1, r631_3 -# 630| r630_7(glval) = VariableAddress[#return] : -# 630| v630_8(void) = ReturnValue : &:r630_7, ~mu630_4 -# 630| v630_9(void) = UnmodeledUse : mu* -# 630| v630_10(void) = AliasedUse : ~mu630_4 -# 630| v630_11(void) = ExitFunction : +# 630| r630_6(glval) = VariableAddress[#return] : +# 630| v630_7(void) = ReturnValue : &:r630_6, ~m? +# 630| v630_8(void) = AliasedUse : ~m? +# 630| v630_9(void) = ExitFunction : # 634| int C::InstanceMemberFunction(int) # 634| Block 0 -# 634| v634_1(void) = EnterFunction : -# 634| mu634_2(unknown) = AliasedDefinition : -# 634| mu634_3(unknown) = InitializeNonLocal : -# 634| mu634_4(unknown) = UnmodeledDefinition : -# 634| r634_5(glval) = InitializeThis : -# 634| r634_6(glval) = VariableAddress[x] : -# 634| mu634_7(int) = InitializeParameter[x] : &:r634_6 -# 635| r635_1(glval) = VariableAddress[#return] : -# 635| r635_2(glval) = VariableAddress[x] : -# 635| r635_3(int) = Load : &:r635_2, ~mu634_4 -# 635| mu635_4(int) = Store : &:r635_1, r635_3 -# 634| r634_8(glval) = VariableAddress[#return] : -# 634| v634_9(void) = ReturnValue : &:r634_8, ~mu634_4 -# 634| v634_10(void) = UnmodeledUse : mu* -# 634| v634_11(void) = AliasedUse : ~mu634_4 -# 634| v634_12(void) = ExitFunction : +# 634| v634_1(void) = EnterFunction : +# 634| mu634_2(unknown) = AliasedDefinition : +# 634| mu634_3(unknown) = InitializeNonLocal : +# 634| r634_4(glval) = VariableAddress[#this] : +# 634| mu634_5(glval) = InitializeParameter[#this] : &:r634_4 +# 634| r634_6(glval) = Load : &:r634_4, ~m? +# 634| mu634_7(C) = InitializeIndirection[#this] : &:r634_6 +# 634| r634_8(glval) = VariableAddress[x] : +# 634| mu634_9(int) = InitializeParameter[x] : &:r634_8 +# 635| r635_1(glval) = VariableAddress[#return] : +# 635| r635_2(glval) = VariableAddress[x] : +# 635| r635_3(int) = Load : &:r635_2, ~m? +# 635| mu635_4(int) = Store : &:r635_1, r635_3 +# 634| v634_10(void) = ReturnIndirection[#this] : &:r634_6, ~m? +# 634| r634_11(glval) = VariableAddress[#return] : +# 634| v634_12(void) = ReturnValue : &:r634_11, ~m? +# 634| v634_13(void) = AliasedUse : ~m? +# 634| v634_14(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 -# 638| v638_1(void) = EnterFunction : -# 638| mu638_2(unknown) = AliasedDefinition : -# 638| mu638_3(unknown) = InitializeNonLocal : -# 638| mu638_4(unknown) = UnmodeledDefinition : -# 638| r638_5(glval) = InitializeThis : -# 638| r638_6(glval) = VariableAddress[x] : -# 638| mu638_7(int) = InitializeParameter[x] : &:r638_6 -# 639| r639_1(glval) = VariableAddress[#return] : -# 639| r639_2(glval) = VariableAddress[x] : -# 639| r639_3(int) = Load : &:r639_2, ~mu638_4 -# 639| mu639_4(int) = Store : &:r639_1, r639_3 -# 638| r638_8(glval) = VariableAddress[#return] : -# 638| v638_9(void) = ReturnValue : &:r638_8, ~mu638_4 -# 638| v638_10(void) = UnmodeledUse : mu* -# 638| v638_11(void) = AliasedUse : ~mu638_4 -# 638| v638_12(void) = ExitFunction : +# 638| v638_1(void) = EnterFunction : +# 638| mu638_2(unknown) = AliasedDefinition : +# 638| mu638_3(unknown) = InitializeNonLocal : +# 638| r638_4(glval) = VariableAddress[#this] : +# 638| mu638_5(glval) = InitializeParameter[#this] : &:r638_4 +# 638| r638_6(glval) = Load : &:r638_4, ~m? +# 638| mu638_7(C) = InitializeIndirection[#this] : &:r638_6 +# 638| r638_8(glval) = VariableAddress[x] : +# 638| mu638_9(int) = InitializeParameter[x] : &:r638_8 +# 639| r639_1(glval) = VariableAddress[#return] : +# 639| r639_2(glval) = VariableAddress[x] : +# 639| r639_3(int) = Load : &:r639_2, ~m? +# 639| mu639_4(int) = Store : &:r639_1, r639_3 +# 638| v638_10(void) = ReturnIndirection[#this] : &:r638_6, ~m? +# 638| r638_11(glval) = VariableAddress[#return] : +# 638| v638_12(void) = ReturnValue : &:r638_11, ~m? +# 638| v638_13(void) = AliasedUse : ~m? +# 638| v638_14(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 -# 642| v642_1(void) = EnterFunction : -# 642| mu642_2(unknown) = AliasedDefinition : -# 642| mu642_3(unknown) = InitializeNonLocal : -# 642| mu642_4(unknown) = UnmodeledDefinition : -# 642| r642_5(glval) = InitializeThis : -# 643| r643_1(int) = Constant[0] : -# 643| r643_2(C *) = CopyValue : r642_5 -# 643| r643_3(glval) = FieldAddress[m_a] : r643_2 -# 643| mu643_4(int) = Store : &:r643_3, r643_1 -# 644| r644_1(int) = Constant[1] : -# 644| r644_2(C *) = CopyValue : r642_5 -# 644| r644_3(glval) = CopyValue : r644_2 -# 644| r644_4(glval) = FieldAddress[m_a] : r644_3 -# 644| mu644_5(int) = Store : &:r644_4, r644_1 -# 645| r645_1(int) = Constant[2] : -#-----| r0_1(C *) = CopyValue : r642_5 -# 645| r645_2(glval) = FieldAddress[m_a] : r0_1 -# 645| mu645_3(int) = Store : &:r645_2, r645_1 -# 646| r646_1(glval) = VariableAddress[x] : -# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 -# 647| r647_1(C *) = CopyValue : r642_5 -# 647| r647_2(glval) = FieldAddress[m_a] : r647_1 -# 647| r647_3(int) = Load : &:r647_2, ~mu642_4 -# 647| r647_4(glval) = VariableAddress[x] : -# 647| mu647_5(int) = Store : &:r647_4, r647_3 -# 648| r648_1(C *) = CopyValue : r642_5 -# 648| r648_2(glval) = CopyValue : r648_1 -# 648| r648_3(glval) = FieldAddress[m_a] : r648_2 -# 648| r648_4(int) = Load : &:r648_3, ~mu642_4 -# 648| r648_5(glval) = VariableAddress[x] : -# 648| mu648_6(int) = Store : &:r648_5, r648_4 -#-----| r0_2(C *) = CopyValue : r642_5 -# 649| r649_1(glval) = FieldAddress[m_a] : r0_2 -# 649| r649_2(int) = Load : &:r649_1, ~mu642_4 -# 649| r649_3(glval) = VariableAddress[x] : -# 649| mu649_4(int) = Store : &:r649_3, r649_2 -# 650| v650_1(void) = NoOp : -# 642| v642_6(void) = ReturnVoid : -# 642| v642_7(void) = UnmodeledUse : mu* -# 642| v642_8(void) = AliasedUse : ~mu642_4 -# 642| v642_9(void) = ExitFunction : +# 642| v642_1(void) = EnterFunction : +# 642| mu642_2(unknown) = AliasedDefinition : +# 642| mu642_3(unknown) = InitializeNonLocal : +# 642| r642_4(glval) = VariableAddress[#this] : +# 642| mu642_5(glval) = InitializeParameter[#this] : &:r642_4 +# 642| r642_6(glval) = Load : &:r642_4, ~m? +# 642| mu642_7(C) = InitializeIndirection[#this] : &:r642_6 +# 643| r643_1(int) = Constant[0] : +# 643| r643_2(glval) = VariableAddress[#this] : +# 643| r643_3(C *) = Load : &:r643_2, ~m? +# 643| r643_4(glval) = FieldAddress[m_a] : r643_3 +# 643| mu643_5(int) = Store : &:r643_4, r643_1 +# 644| r644_1(int) = Constant[1] : +# 644| r644_2(glval) = VariableAddress[#this] : +# 644| r644_3(C *) = Load : &:r644_2, ~m? +# 644| r644_4(glval) = CopyValue : r644_3 +# 644| r644_5(glval) = FieldAddress[m_a] : r644_4 +# 644| mu644_6(int) = Store : &:r644_5, r644_1 +# 645| r645_1(int) = Constant[2] : +# 645| r645_2(glval) = VariableAddress[#this] : +# 645| r645_3(C *) = Load : &:r645_2, ~m? +# 645| r645_4(glval) = FieldAddress[m_a] : r645_3 +# 645| mu645_5(int) = Store : &:r645_4, r645_1 +# 646| r646_1(glval) = VariableAddress[x] : +# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 +# 647| r647_1(glval) = VariableAddress[#this] : +# 647| r647_2(C *) = Load : &:r647_1, ~m? +# 647| r647_3(glval) = FieldAddress[m_a] : r647_2 +# 647| r647_4(int) = Load : &:r647_3, ~m? +# 647| r647_5(glval) = VariableAddress[x] : +# 647| mu647_6(int) = Store : &:r647_5, r647_4 +# 648| r648_1(glval) = VariableAddress[#this] : +# 648| r648_2(C *) = Load : &:r648_1, ~m? +# 648| r648_3(glval) = CopyValue : r648_2 +# 648| r648_4(glval) = FieldAddress[m_a] : r648_3 +# 648| r648_5(int) = Load : &:r648_4, ~m? +# 648| r648_6(glval) = VariableAddress[x] : +# 648| mu648_7(int) = Store : &:r648_6, r648_5 +# 649| r649_1(glval) = VariableAddress[#this] : +# 649| r649_2(C *) = Load : &:r649_1, ~m? +# 649| r649_3(glval) = FieldAddress[m_a] : r649_2 +# 649| r649_4(int) = Load : &:r649_3, ~m? +# 649| r649_5(glval) = VariableAddress[x] : +# 649| mu649_6(int) = Store : &:r649_5, r649_4 +# 650| v650_1(void) = NoOp : +# 642| v642_8(void) = ReturnIndirection[#this] : &:r642_6, ~m? +# 642| v642_9(void) = ReturnVoid : +# 642| v642_10(void) = AliasedUse : ~m? +# 642| v642_11(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 # 652| v652_1(void) = EnterFunction : # 652| mu652_2(unknown) = AliasedDefinition : # 652| mu652_3(unknown) = InitializeNonLocal : -# 652| mu652_4(unknown) = UnmodeledDefinition : -# 652| r652_5(glval) = InitializeThis : -# 653| r653_1(C *) = CopyValue : r652_5 -# 653| r653_2(glval) = FunctionAddress[InstanceMemberFunction] : -# 653| r653_3(int) = Constant[0] : -# 653| r653_4(int) = Call : func:r653_2, this:r653_1, 0:r653_3 -# 653| mu653_5(unknown) = ^CallSideEffect : ~mu652_4 -# 653| v653_6(void) = ^BufferReadSideEffect[-1] : &:r653_1, ~mu652_4 -# 653| mu653_7(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_1 -# 654| r654_1(C *) = CopyValue : r652_5 -# 654| r654_2(glval) = CopyValue : r654_1 -# 654| r654_3(glval) = FunctionAddress[InstanceMemberFunction] : -# 654| r654_4(int) = Constant[1] : -# 654| r654_5(int) = Call : func:r654_3, this:r654_2, 0:r654_4 -# 654| mu654_6(unknown) = ^CallSideEffect : ~mu652_4 -# 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~mu652_4 -# 654| mu654_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_2 -#-----| r0_1(C *) = CopyValue : r652_5 -# 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : -# 655| r655_2(int) = Constant[2] : -# 655| r655_3(int) = Call : func:r655_1, this:r0_1, 0:r655_2 -# 655| mu655_4(unknown) = ^CallSideEffect : ~mu652_4 -#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~mu652_4 -#-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 +# 652| r652_4(glval) = VariableAddress[#this] : +# 652| mu652_5(glval) = InitializeParameter[#this] : &:r652_4 +# 652| r652_6(glval) = Load : &:r652_4, ~m? +# 652| mu652_7(C) = InitializeIndirection[#this] : &:r652_6 +# 653| r653_1(glval) = VariableAddress[#this] : +# 653| r653_2(C *) = Load : &:r653_1, ~m? +# 653| r653_3(glval) = FunctionAddress[InstanceMemberFunction] : +# 653| r653_4(int) = Constant[0] : +# 653| r653_5(int) = Call : func:r653_3, this:r653_2, 0:r653_4 +# 653| mu653_6(unknown) = ^CallSideEffect : ~m? +# 653| v653_7(void) = ^BufferReadSideEffect[-1] : &:r653_2, ~m? +# 653| mu653_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_2 +# 654| r654_1(glval) = VariableAddress[#this] : +# 654| r654_2(C *) = Load : &:r654_1, ~m? +# 654| r654_3(glval) = CopyValue : r654_2 +# 654| r654_4(glval) = FunctionAddress[InstanceMemberFunction] : +# 654| r654_5(int) = Constant[1] : +# 654| r654_6(int) = Call : func:r654_4, this:r654_3, 0:r654_5 +# 654| mu654_7(unknown) = ^CallSideEffect : ~m? +# 654| v654_8(void) = ^BufferReadSideEffect[-1] : &:r654_3, ~m? +# 654| mu654_9(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_3 +# 655| r655_1(glval) = VariableAddress[#this] : +# 655| r655_2(C *) = Load : &:r655_1, ~m? +# 655| r655_3(glval) = FunctionAddress[InstanceMemberFunction] : +# 655| r655_4(int) = Constant[2] : +# 655| r655_5(int) = Call : func:r655_3, this:r655_2, 0:r655_4 +# 655| mu655_6(unknown) = ^CallSideEffect : ~m? +# 655| v655_7(void) = ^BufferReadSideEffect[-1] : &:r655_2, ~m? +# 655| mu655_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r655_2 # 656| v656_1(void) = NoOp : -# 652| v652_6(void) = ReturnVoid : -# 652| v652_7(void) = UnmodeledUse : mu* -# 652| v652_8(void) = AliasedUse : ~mu652_4 -# 652| v652_9(void) = ExitFunction : +# 652| v652_8(void) = ReturnIndirection[#this] : &:r652_6, ~m? +# 652| v652_9(void) = ReturnVoid : +# 652| v652_10(void) = AliasedUse : ~m? +# 652| v652_11(void) = ExitFunction : # 658| void C::C() # 658| Block 0 # 658| v658_1(void) = EnterFunction : # 658| mu658_2(unknown) = AliasedDefinition : # 658| mu658_3(unknown) = InitializeNonLocal : -# 658| mu658_4(unknown) = UnmodeledDefinition : -# 658| r658_5(glval) = InitializeThis : -# 659| r659_1(glval) = FieldAddress[m_a] : r658_5 +# 658| r658_4(glval) = VariableAddress[#this] : +# 658| mu658_5(glval) = InitializeParameter[#this] : &:r658_4 +# 658| r658_6(glval) = Load : &:r658_4, ~m? +# 658| mu658_7(C) = InitializeIndirection[#this] : &:r658_6 +# 659| r659_1(glval) = FieldAddress[m_a] : mu658_5 # 659| r659_2(int) = Constant[1] : # 659| mu659_3(int) = Store : &:r659_1, r659_2 -# 663| r663_1(glval) = FieldAddress[m_b] : r658_5 +# 663| r663_1(glval) = FieldAddress[m_b] : mu658_5 # 663| r663_2(glval) = FunctionAddress[String] : # 663| v663_3(void) = Call : func:r663_2, this:r663_1 -# 663| mu663_4(unknown) = ^CallSideEffect : ~mu658_4 +# 663| mu663_4(unknown) = ^CallSideEffect : ~m? # 663| mu663_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r663_1 -# 660| r660_1(glval) = FieldAddress[m_c] : r658_5 +# 660| r660_1(glval) = FieldAddress[m_c] : mu658_5 # 660| r660_2(char) = Constant[3] : # 660| mu660_3(char) = Store : &:r660_1, r660_2 -# 661| r661_1(glval) = FieldAddress[m_e] : r658_5 +# 661| r661_1(glval) = FieldAddress[m_e] : mu658_5 # 661| r661_2(void *) = Constant[0] : # 661| mu661_3(void *) = Store : &:r661_1, r661_2 -# 662| r662_1(glval) = FieldAddress[m_f] : r658_5 +# 662| r662_1(glval) = FieldAddress[m_f] : mu658_5 # 662| r662_2(glval) = FunctionAddress[String] : # 662| r662_3(glval) = StringConstant["test"] : # 662| r662_4(char *) = Convert : r662_3 # 662| v662_5(void) = Call : func:r662_2, this:r662_1, 0:r662_4 -# 662| mu662_6(unknown) = ^CallSideEffect : ~mu658_4 +# 662| mu662_6(unknown) = ^CallSideEffect : ~m? # 662| mu662_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r662_1 -# 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~mu658_4 +# 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : -# 658| v658_6(void) = ReturnVoid : -# 658| v658_7(void) = UnmodeledUse : mu* -# 658| v658_8(void) = AliasedUse : ~mu658_4 -# 658| v658_9(void) = ExitFunction : +# 658| v658_8(void) = ReturnIndirection[#this] : &:r658_6, ~m? +# 658| v658_9(void) = ReturnVoid : +# 658| v658_10(void) = AliasedUse : ~m? +# 658| v658_11(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 # 675| v675_1(void) = EnterFunction : # 675| mu675_2(unknown) = AliasedDefinition : # 675| mu675_3(unknown) = InitializeNonLocal : -# 675| mu675_4(unknown) = UnmodeledDefinition : -# 675| r675_5(glval) = VariableAddress[r] : -# 675| mu675_6(int &) = InitializeParameter[r] : &:r675_5 -# 675| r675_7(int &) = Load : &:r675_5, ~mu675_4 -# 675| mu675_8(unknown) = InitializeIndirection[r] : &:r675_7 +# 675| r675_4(glval) = VariableAddress[r] : +# 675| mu675_5(int &) = InitializeParameter[r] : &:r675_4 +# 675| r675_6(int &) = Load : &:r675_4, ~m? +# 675| mu675_7(unknown) = InitializeIndirection[r] : &:r675_6 # 676| r676_1(glval) = VariableAddress[#return] : # 676| r676_2(glval) = VariableAddress[r] : -# 676| r676_3(int &) = Load : &:r676_2, ~mu675_4 -# 676| r676_4(int) = Load : &:r676_3, ~mu675_4 +# 676| r676_3(int &) = Load : &:r676_2, ~m? +# 676| r676_4(int) = Load : &:r676_3, ~m? # 676| mu676_5(int) = Store : &:r676_1, r676_4 -# 675| v675_9(void) = ReturnIndirection[r] : &:r675_7, ~mu675_4 -# 675| r675_10(glval) = VariableAddress[#return] : -# 675| v675_11(void) = ReturnValue : &:r675_10, ~mu675_4 -# 675| v675_12(void) = UnmodeledUse : mu* -# 675| v675_13(void) = AliasedUse : ~mu675_4 -# 675| v675_14(void) = ExitFunction : +# 675| v675_8(void) = ReturnIndirection[r] : &:r675_6, ~m? +# 675| r675_9(glval) = VariableAddress[#return] : +# 675| v675_10(void) = ReturnValue : &:r675_9, ~m? +# 675| v675_11(void) = AliasedUse : ~m? +# 675| v675_12(void) = ExitFunction : # 679| int& TakeReference() # 679| Block 0 # 679| v679_1(void) = EnterFunction : # 679| mu679_2(unknown) = AliasedDefinition : # 679| mu679_3(unknown) = InitializeNonLocal : -# 679| mu679_4(unknown) = UnmodeledDefinition : # 680| r680_1(glval) = VariableAddress[#return] : # 680| r680_2(glval) = VariableAddress[g] : # 680| r680_3(int &) = CopyValue : r680_2 # 680| mu680_4(int &) = Store : &:r680_1, r680_3 -# 679| r679_5(glval) = VariableAddress[#return] : -# 679| v679_6(void) = ReturnValue : &:r679_5, ~mu679_4 -# 679| v679_7(void) = UnmodeledUse : mu* -# 679| v679_8(void) = AliasedUse : ~mu679_4 -# 679| v679_9(void) = ExitFunction : +# 679| r679_4(glval) = VariableAddress[#return] : +# 679| v679_5(void) = ReturnValue : &:r679_4, ~m? +# 679| v679_6(void) = AliasedUse : ~m? +# 679| v679_7(void) = ExitFunction : # 685| void InitReference(int) # 685| Block 0 # 685| v685_1(void) = EnterFunction : # 685| mu685_2(unknown) = AliasedDefinition : # 685| mu685_3(unknown) = InitializeNonLocal : -# 685| mu685_4(unknown) = UnmodeledDefinition : -# 685| r685_5(glval) = VariableAddress[x] : -# 685| mu685_6(int) = InitializeParameter[x] : &:r685_5 +# 685| r685_4(glval) = VariableAddress[x] : +# 685| mu685_5(int) = InitializeParameter[x] : &:r685_4 # 686| r686_1(glval) = VariableAddress[r] : # 686| r686_2(glval) = VariableAddress[x] : # 686| r686_3(int &) = CopyValue : r686_2 # 686| mu686_4(int &) = Store : &:r686_1, r686_3 # 687| r687_1(glval) = VariableAddress[r2] : # 687| r687_2(glval) = VariableAddress[r] : -# 687| r687_3(int &) = Load : &:r687_2, ~mu685_4 +# 687| r687_3(int &) = Load : &:r687_2, ~m? # 687| r687_4(glval) = CopyValue : r687_3 # 687| r687_5(int &) = CopyValue : r687_4 # 687| mu687_6(int &) = Store : &:r687_1, r687_5 # 688| r688_1(glval) = VariableAddress[r3] : # 688| r688_2(glval) = FunctionAddress[ReturnReference] : # 688| r688_3(String &) = Call : func:r688_2 -# 688| mu688_4(unknown) = ^CallSideEffect : ~mu685_4 +# 688| mu688_4(unknown) = ^CallSideEffect : ~m? # 688| r688_5(glval) = CopyValue : r688_3 # 688| r688_6(glval) = Convert : r688_5 # 688| r688_7(String &) = CopyValue : r688_6 # 688| mu688_8(String &) = Store : &:r688_1, r688_7 # 689| v689_1(void) = NoOp : -# 685| v685_7(void) = ReturnVoid : -# 685| v685_8(void) = UnmodeledUse : mu* -# 685| v685_9(void) = AliasedUse : ~mu685_4 -# 685| v685_10(void) = ExitFunction : +# 685| v685_6(void) = ReturnVoid : +# 685| v685_7(void) = AliasedUse : ~m? +# 685| v685_8(void) = ExitFunction : # 691| void ArrayReferences() # 691| Block 0 # 691| v691_1(void) = EnterFunction : # 691| mu691_2(unknown) = AliasedDefinition : # 691| mu691_3(unknown) = InitializeNonLocal : -# 691| mu691_4(unknown) = UnmodeledDefinition : # 692| r692_1(glval) = VariableAddress[a] : # 692| mu692_2(int[10]) = Uninitialized[a] : &:r692_1 # 693| r693_1(glval) = VariableAddress[ra] : @@ -3841,61 +3720,57 @@ ir.cpp: # 693| mu693_4(int(&)[10]) = Store : &:r693_1, r693_3 # 694| r694_1(glval) = VariableAddress[x] : # 694| r694_2(glval) = VariableAddress[ra] : -# 694| r694_3(int(&)[10]) = Load : &:r694_2, ~mu691_4 +# 694| r694_3(int(&)[10]) = Load : &:r694_2, ~m? # 694| r694_4(glval) = CopyValue : r694_3 # 694| r694_5(int *) = Convert : r694_4 # 694| r694_6(int) = Constant[5] : # 694| r694_7(glval) = PointerAdd[4] : r694_5, r694_6 -# 694| r694_8(int) = Load : &:r694_7, ~mu691_4 +# 694| r694_8(int) = Load : &:r694_7, ~m? # 694| mu694_9(int) = Store : &:r694_1, r694_8 # 695| v695_1(void) = NoOp : -# 691| v691_5(void) = ReturnVoid : -# 691| v691_6(void) = UnmodeledUse : mu* -# 691| v691_7(void) = AliasedUse : ~mu691_4 -# 691| v691_8(void) = ExitFunction : +# 691| v691_4(void) = ReturnVoid : +# 691| v691_5(void) = AliasedUse : ~m? +# 691| v691_6(void) = ExitFunction : # 697| void FunctionReferences() # 697| Block 0 # 697| v697_1(void) = EnterFunction : # 697| mu697_2(unknown) = AliasedDefinition : # 697| mu697_3(unknown) = InitializeNonLocal : -# 697| mu697_4(unknown) = UnmodeledDefinition : # 698| r698_1(glval<..(&)(..)>) = VariableAddress[rfn] : # 698| r698_2(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : # 698| r698_3(..(&)(..)) = CopyValue : r698_2 # 698| mu698_4(..(&)(..)) = Store : &:r698_1, r698_3 # 699| r699_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 699| r699_2(glval<..(&)(..)>) = VariableAddress[rfn] : -# 699| r699_3(..(&)(..)) = Load : &:r699_2, ~mu697_4 +# 699| r699_3(..(&)(..)) = Load : &:r699_2, ~m? # 699| r699_4(..(*)(..)) = CopyValue : r699_3 # 699| mu699_5(..(*)(..)) = Store : &:r699_1, r699_4 # 700| r700_1(glval<..(&)(..)>) = VariableAddress[rfn] : -# 700| r700_2(..(&)(..)) = Load : &:r700_1, ~mu697_4 +# 700| r700_2(..(&)(..)) = Load : &:r700_1, ~m? # 700| r700_3(..(*)(..)) = CopyValue : r700_2 # 700| r700_4(int) = Constant[5] : # 700| r700_5(int) = Call : func:r700_3, 0:r700_4 -# 700| mu700_6(unknown) = ^CallSideEffect : ~mu697_4 +# 700| mu700_6(unknown) = ^CallSideEffect : ~m? # 701| v701_1(void) = NoOp : -# 697| v697_5(void) = ReturnVoid : -# 697| v697_6(void) = UnmodeledUse : mu* -# 697| v697_7(void) = AliasedUse : ~mu697_4 -# 697| v697_8(void) = ExitFunction : +# 697| v697_4(void) = ReturnVoid : +# 697| v697_5(void) = AliasedUse : ~m? +# 697| v697_6(void) = ExitFunction : # 704| int min(int, int) # 704| Block 0 # 704| v704_1(void) = EnterFunction : # 704| mu704_2(unknown) = AliasedDefinition : # 704| mu704_3(unknown) = InitializeNonLocal : -# 704| mu704_4(unknown) = UnmodeledDefinition : -# 704| r704_5(glval) = VariableAddress[x] : -# 704| mu704_6(int) = InitializeParameter[x] : &:r704_5 -# 704| r704_7(glval) = VariableAddress[y] : -# 704| mu704_8(int) = InitializeParameter[y] : &:r704_7 +# 704| r704_4(glval) = VariableAddress[x] : +# 704| mu704_5(int) = InitializeParameter[x] : &:r704_4 +# 704| r704_6(glval) = VariableAddress[y] : +# 704| mu704_7(int) = InitializeParameter[y] : &:r704_6 # 705| r705_1(glval) = VariableAddress[#return] : # 705| r705_2(glval) = VariableAddress[x] : -# 705| r705_3(int) = Load : &:r705_2, ~mu704_4 +# 705| r705_3(int) = Load : &:r705_2, ~m? # 705| r705_4(glval) = VariableAddress[y] : -# 705| r705_5(int) = Load : &:r705_4, ~mu704_4 +# 705| r705_5(int) = Load : &:r705_4, ~m? # 705| r705_6(bool) = CompareLT : r705_3, r705_5 # 705| v705_7(void) = ConditionalBranch : r705_6 #-----| False -> Block 2 @@ -3903,121 +3778,112 @@ ir.cpp: # 705| Block 1 # 705| r705_8(glval) = VariableAddress[x] : -# 705| r705_9(int) = Load : &:r705_8, ~mu704_4 +# 705| r705_9(int) = Load : &:r705_8, ~m? # 705| r705_10(glval) = VariableAddress[#temp705:10] : # 705| mu705_11(int) = Store : &:r705_10, r705_9 #-----| Goto -> Block 3 # 705| Block 2 # 705| r705_12(glval) = VariableAddress[y] : -# 705| r705_13(int) = Load : &:r705_12, ~mu704_4 +# 705| r705_13(int) = Load : &:r705_12, ~m? # 705| r705_14(glval) = VariableAddress[#temp705:10] : # 705| mu705_15(int) = Store : &:r705_14, r705_13 #-----| Goto -> Block 3 # 705| Block 3 # 705| r705_16(glval) = VariableAddress[#temp705:10] : -# 705| r705_17(int) = Load : &:r705_16, ~mu704_4 +# 705| r705_17(int) = Load : &:r705_16, ~m? # 705| mu705_18(int) = Store : &:r705_1, r705_17 -# 704| r704_9(glval) = VariableAddress[#return] : -# 704| v704_10(void) = ReturnValue : &:r704_9, ~mu704_4 -# 704| v704_11(void) = UnmodeledUse : mu* -# 704| v704_12(void) = AliasedUse : ~mu704_4 -# 704| v704_13(void) = ExitFunction : +# 704| r704_8(glval) = VariableAddress[#return] : +# 704| v704_9(void) = ReturnValue : &:r704_8, ~m? +# 704| v704_10(void) = AliasedUse : ~m? +# 704| v704_11(void) = ExitFunction : # 708| int CallMin(int, int) # 708| Block 0 # 708| v708_1(void) = EnterFunction : # 708| mu708_2(unknown) = AliasedDefinition : # 708| mu708_3(unknown) = InitializeNonLocal : -# 708| mu708_4(unknown) = UnmodeledDefinition : -# 708| r708_5(glval) = VariableAddress[x] : -# 708| mu708_6(int) = InitializeParameter[x] : &:r708_5 -# 708| r708_7(glval) = VariableAddress[y] : -# 708| mu708_8(int) = InitializeParameter[y] : &:r708_7 +# 708| r708_4(glval) = VariableAddress[x] : +# 708| mu708_5(int) = InitializeParameter[x] : &:r708_4 +# 708| r708_6(glval) = VariableAddress[y] : +# 708| mu708_7(int) = InitializeParameter[y] : &:r708_6 # 709| r709_1(glval) = VariableAddress[#return] : # 709| r709_2(glval) = FunctionAddress[min] : # 709| r709_3(glval) = VariableAddress[x] : -# 709| r709_4(int) = Load : &:r709_3, ~mu708_4 +# 709| r709_4(int) = Load : &:r709_3, ~m? # 709| r709_5(glval) = VariableAddress[y] : -# 709| r709_6(int) = Load : &:r709_5, ~mu708_4 +# 709| r709_6(int) = Load : &:r709_5, ~m? # 709| r709_7(int) = Call : func:r709_2, 0:r709_4, 1:r709_6 -# 709| mu709_8(unknown) = ^CallSideEffect : ~mu708_4 +# 709| mu709_8(unknown) = ^CallSideEffect : ~m? # 709| mu709_9(int) = Store : &:r709_1, r709_7 -# 708| r708_9(glval) = VariableAddress[#return] : -# 708| v708_10(void) = ReturnValue : &:r708_9, ~mu708_4 -# 708| v708_11(void) = UnmodeledUse : mu* -# 708| v708_12(void) = AliasedUse : ~mu708_4 -# 708| v708_13(void) = ExitFunction : +# 708| r708_8(glval) = VariableAddress[#return] : +# 708| v708_9(void) = ReturnValue : &:r708_8, ~m? +# 708| v708_10(void) = AliasedUse : ~m? +# 708| v708_11(void) = ExitFunction : # 715| long Outer::Func(void*, char) # 715| Block 0 # 715| v715_1(void) = EnterFunction : # 715| mu715_2(unknown) = AliasedDefinition : # 715| mu715_3(unknown) = InitializeNonLocal : -# 715| mu715_4(unknown) = UnmodeledDefinition : -# 715| r715_5(glval) = VariableAddress[x] : -# 715| mu715_6(void *) = InitializeParameter[x] : &:r715_5 -# 715| r715_7(void *) = Load : &:r715_5, ~mu715_4 -# 715| mu715_8(unknown) = InitializeIndirection[x] : &:r715_7 -# 715| r715_9(glval) = VariableAddress[y] : -# 715| mu715_10(char) = InitializeParameter[y] : &:r715_9 +# 715| r715_4(glval) = VariableAddress[x] : +# 715| mu715_5(void *) = InitializeParameter[x] : &:r715_4 +# 715| r715_6(void *) = Load : &:r715_4, ~m? +# 715| mu715_7(unknown) = InitializeIndirection[x] : &:r715_6 +# 715| r715_8(glval) = VariableAddress[y] : +# 715| mu715_9(char) = InitializeParameter[y] : &:r715_8 # 716| r716_1(glval) = VariableAddress[#return] : # 716| r716_2(long) = Constant[0] : # 716| mu716_3(long) = Store : &:r716_1, r716_2 -# 715| v715_11(void) = ReturnIndirection[x] : &:r715_7, ~mu715_4 -# 715| r715_12(glval) = VariableAddress[#return] : -# 715| v715_13(void) = ReturnValue : &:r715_12, ~mu715_4 -# 715| v715_14(void) = UnmodeledUse : mu* -# 715| v715_15(void) = AliasedUse : ~mu715_4 -# 715| v715_16(void) = ExitFunction : +# 715| v715_10(void) = ReturnIndirection[x] : &:r715_6, ~m? +# 715| r715_11(glval) = VariableAddress[#return] : +# 715| v715_12(void) = ReturnValue : &:r715_11, ~m? +# 715| v715_13(void) = AliasedUse : ~m? +# 715| v715_14(void) = ExitFunction : # 720| double CallNestedTemplateFunc() # 720| Block 0 # 720| v720_1(void) = EnterFunction : # 720| mu720_2(unknown) = AliasedDefinition : # 720| mu720_3(unknown) = InitializeNonLocal : -# 720| mu720_4(unknown) = UnmodeledDefinition : # 721| r721_1(glval) = VariableAddress[#return] : # 721| r721_2(glval) = FunctionAddress[Func] : # 721| r721_3(void *) = Constant[0] : # 721| r721_4(char) = Constant[111] : # 721| r721_5(long) = Call : func:r721_2, 0:r721_3, 1:r721_4 -# 721| mu721_6(unknown) = ^CallSideEffect : ~mu720_4 -# 721| v721_7(void) = ^BufferReadSideEffect[0] : &:r721_3, ~mu720_4 +# 721| mu721_6(unknown) = ^CallSideEffect : ~m? +# 721| v721_7(void) = ^BufferReadSideEffect[0] : &:r721_3, ~m? # 721| mu721_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r721_3 # 721| r721_9(double) = Convert : r721_5 # 721| mu721_10(double) = Store : &:r721_1, r721_9 -# 720| r720_5(glval) = VariableAddress[#return] : -# 720| v720_6(void) = ReturnValue : &:r720_5, ~mu720_4 -# 720| v720_7(void) = UnmodeledUse : mu* -# 720| v720_8(void) = AliasedUse : ~mu720_4 -# 720| v720_9(void) = ExitFunction : +# 720| r720_4(glval) = VariableAddress[#return] : +# 720| v720_5(void) = ReturnValue : &:r720_4, ~m? +# 720| v720_6(void) = AliasedUse : ~m? +# 720| v720_7(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 # 724| v724_1(void) = EnterFunction : # 724| mu724_2(unknown) = AliasedDefinition : # 724| mu724_3(unknown) = InitializeNonLocal : -# 724| mu724_4(unknown) = UnmodeledDefinition : -# 724| r724_5(glval) = VariableAddress[b] : -# 724| mu724_6(bool) = InitializeParameter[b] : &:r724_5 +# 724| r724_4(glval) = VariableAddress[b] : +# 724| mu724_5(bool) = InitializeParameter[b] : &:r724_4 # 726| r726_1(glval) = VariableAddress[x] : # 726| r726_2(int) = Constant[5] : # 726| mu726_3(int) = Store : &:r726_1, r726_2 # 727| r727_1(glval) = VariableAddress[b] : -# 727| r727_2(bool) = Load : &:r727_1, ~mu724_4 +# 727| r727_2(bool) = Load : &:r727_1, ~m? # 727| v727_3(void) = ConditionalBranch : r727_2 #-----| False -> Block 4 #-----| True -> Block 3 # 724| Block 1 -# 724| v724_7(void) = UnmodeledUse : mu* -# 724| v724_8(void) = AliasedUse : ~mu724_4 -# 724| v724_9(void) = ExitFunction : +# 724| v724_6(void) = AliasedUse : ~m? +# 724| v724_7(void) = ExitFunction : # 724| Block 2 -# 724| v724_10(void) = Unwind : +# 724| v724_8(void) = Unwind : #-----| Goto -> Block 1 # 728| Block 3 @@ -4025,12 +3891,12 @@ ir.cpp: # 728| r728_2(glval) = StringConstant["string literal"] : # 728| r728_3(char *) = Convert : r728_2 # 728| mu728_4(char *) = Store : &:r728_1, r728_3 -# 728| v728_5(void) = ThrowValue : &:r728_1, ~mu724_4 +# 728| v728_5(void) = ThrowValue : &:r728_1, ~m? #-----| Exception -> Block 9 # 730| Block 4 # 730| r730_1(glval) = VariableAddress[x] : -# 730| r730_2(int) = Load : &:r730_1, ~mu724_4 +# 730| r730_2(int) = Load : &:r730_1, ~m? # 730| r730_3(int) = Constant[2] : # 730| r730_4(bool) = CompareLT : r730_2, r730_3 # 730| v730_5(void) = ConditionalBranch : r730_4 @@ -4039,7 +3905,7 @@ ir.cpp: # 731| Block 5 # 731| r731_1(glval) = VariableAddress[b] : -# 731| r731_2(bool) = Load : &:r731_1, ~mu724_4 +# 731| r731_2(bool) = Load : &:r731_1, ~m? # 731| v731_3(void) = ConditionalBranch : r731_2 #-----| False -> Block 7 #-----| True -> Block 6 @@ -4049,7 +3915,7 @@ ir.cpp: # 731| r731_5(glval) = VariableAddress[#temp731:11] : # 731| mu731_6(int) = Store : &:r731_5, r731_4 # 731| r731_7(glval) = VariableAddress[#temp731:11] : -# 731| r731_8(int) = Load : &:r731_7, ~mu724_4 +# 731| r731_8(int) = Load : &:r731_7, ~m? # 731| r731_9(glval) = VariableAddress[x] : # 731| mu731_10(int) = Store : &:r731_9, r731_8 #-----| Goto -> Block 8 @@ -4061,11 +3927,11 @@ ir.cpp: # 731| r731_14(glval) = StringConstant["String object"] : # 731| r731_15(char *) = Convert : r731_14 # 731| v731_16(void) = Call : func:r731_13, this:r731_11, 0:r731_15 -# 731| mu731_17(unknown) = ^CallSideEffect : ~mu724_4 +# 731| mu731_17(unknown) = ^CallSideEffect : ~m? # 731| mu731_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11 -# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~mu724_4 +# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~m? # 731| mu731_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r731_15 -# 731| v731_21(void) = ThrowValue : &:r731_11, ~mu724_4 +# 731| v731_21(void) = ThrowValue : &:r731_11, ~m? #-----| Exception -> Block 9 # 733| Block 8 @@ -4082,19 +3948,19 @@ ir.cpp: # 735| Block 10 # 735| r735_2(glval) = VariableAddress[s] : # 735| mu735_3(char *) = InitializeParameter[s] : &:r735_2 -# 735| r735_4(char *) = Load : &:r735_2, ~mu724_4 +# 735| r735_4(char *) = Load : &:r735_2, ~m? # 735| mu735_5(unknown) = InitializeIndirection[s] : &:r735_4 # 736| r736_1(glval) = VariableAddress[#throw736:5] : # 736| mu736_2(String) = Uninitialized[#throw736:5] : &:r736_1 # 736| r736_3(glval) = FunctionAddress[String] : # 736| r736_4(glval) = VariableAddress[s] : -# 736| r736_5(char *) = Load : &:r736_4, ~mu724_4 +# 736| r736_5(char *) = Load : &:r736_4, ~m? # 736| v736_6(void) = Call : func:r736_3, this:r736_1, 0:r736_5 -# 736| mu736_7(unknown) = ^CallSideEffect : ~mu724_4 +# 736| mu736_7(unknown) = ^CallSideEffect : ~m? # 736| mu736_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1 -# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~mu724_4 +# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~m? # 736| mu736_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r736_5 -# 736| v736_11(void) = ThrowValue : &:r736_1, ~mu724_4 +# 736| v736_11(void) = ThrowValue : &:r736_1, ~m? #-----| Exception -> Block 2 # 738| Block 11 @@ -4105,7 +3971,7 @@ ir.cpp: # 738| Block 12 # 738| r738_2(glval) = VariableAddress[e] : # 738| mu738_3(String &) = InitializeParameter[e] : &:r738_2 -# 738| r738_4(String &) = Load : &:r738_2, ~mu724_4 +# 738| r738_4(String &) = Load : &:r738_2, ~m? # 738| mu738_5(unknown) = InitializeIndirection[e] : &:r738_4 # 738| v738_6(void) = NoOp : #-----| Goto -> Block 14 @@ -4116,480 +3982,519 @@ ir.cpp: #-----| Exception -> Block 2 # 743| Block 14 -# 743| v743_1(void) = NoOp : -# 724| v724_11(void) = ReturnVoid : +# 743| v743_1(void) = NoOp : +# 724| v724_9(void) = ReturnVoid : #-----| Goto -> Block 1 # 745| Base& Base::operator=(Base const&) # 745| Block 0 -# 745| v745_1(void) = EnterFunction : -# 745| mu745_2(unknown) = AliasedDefinition : -# 745| mu745_3(unknown) = InitializeNonLocal : -# 745| mu745_4(unknown) = UnmodeledDefinition : -# 745| r745_5(glval) = InitializeThis : -#-----| r0_1(glval) = VariableAddress[p#0] : -#-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 -#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Base *) = CopyValue : r745_5 -#-----| r0_6(glval) = FieldAddress[base_s] : r0_5 -#-----| r0_7(String *) = CopyValue : r0_6 -# 745| r745_6(glval) = FunctionAddress[operator=] : -#-----| r0_8(glval) = VariableAddress[p#0] : -#-----| r0_9(Base &) = Load : &:r0_8, ~mu745_4 -#-----| r0_10(glval) = CopyValue : r0_9 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -#-----| r0_12(String &) = CopyValue : r0_11 -# 745| r745_7(String &) = Call : func:r745_6, this:r0_7, 0:r0_12 -# 745| mu745_8(unknown) = ^CallSideEffect : ~mu745_4 -#-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~mu745_4 -#-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~mu745_4 -#-----| mu0_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 -#-----| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 -#-----| r0_17(glval) = CopyValue : r745_7 -#-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r745_5 -#-----| r0_20(glval) = CopyValue : r0_19 -#-----| r0_21(Base &) = CopyValue : r0_20 -#-----| mu0_22(Base &) = Store : &:r0_18, r0_21 -#-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 -# 745| r745_9(glval) = VariableAddress[#return] : -# 745| v745_10(void) = ReturnValue : &:r745_9, ~mu745_4 -# 745| v745_11(void) = UnmodeledUse : mu* -# 745| v745_12(void) = AliasedUse : ~mu745_4 -# 745| v745_13(void) = ExitFunction : +# 745| v745_1(void) = EnterFunction : +# 745| mu745_2(unknown) = AliasedDefinition : +# 745| mu745_3(unknown) = InitializeNonLocal : +# 745| r745_4(glval) = VariableAddress[#this] : +# 745| mu745_5(glval) = InitializeParameter[#this] : &:r745_4 +# 745| r745_6(glval) = Load : &:r745_4, ~m? +# 745| mu745_7(Base) = InitializeIndirection[#this] : &:r745_6 +#-----| r0_1(glval) = VariableAddress[p#0] : +#-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 +#-----| r0_3(Base &) = Load : &:r0_1, ~m? +#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 +# 745| r745_8(glval) = VariableAddress[#this] : +# 745| r745_9(Base *) = Load : &:r745_8, ~m? +# 745| r745_10(glval) = FieldAddress[base_s] : r745_9 +# 745| r745_11(String *) = CopyValue : r745_10 +# 745| r745_12(glval) = FunctionAddress[operator=] : +# 745| r745_13(glval) = VariableAddress[p#0] : +# 745| r745_14(Base &) = Load : &:r745_13, ~m? +#-----| r0_5(glval) = CopyValue : r745_14 +# 745| r745_15(glval) = FieldAddress[base_s] : r0_5 +#-----| r0_6(String &) = CopyValue : r745_15 +# 745| r745_16(String &) = Call : func:r745_12, this:r745_11, 0:r0_6 +# 745| mu745_17(unknown) = ^CallSideEffect : ~m? +# 745| v745_18(void) = ^BufferReadSideEffect[-1] : &:r745_11, ~m? +#-----| v0_7(void) = ^BufferReadSideEffect[0] : &:r0_6, ~m? +# 745| mu745_19(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_11 +#-----| mu0_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 +#-----| r0_9(glval) = CopyValue : r745_16 +#-----| r0_10(glval) = VariableAddress[#return] : +#-----| r0_11(glval) = VariableAddress[#this] : +#-----| r0_12(Base *) = Load : &:r0_11, ~m? +#-----| r0_13(glval) = CopyValue : r0_12 +#-----| r0_14(Base &) = CopyValue : r0_13 +#-----| mu0_15(Base &) = Store : &:r0_10, r0_14 +# 745| v745_20(void) = ReturnIndirection[#this] : &:r745_6, ~m? +#-----| v0_16(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 745| r745_21(glval) = VariableAddress[#return] : +# 745| v745_22(void) = ReturnValue : &:r745_21, ~m? +# 745| v745_23(void) = AliasedUse : ~m? +# 745| v745_24(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 # 745| v745_1(void) = EnterFunction : # 745| mu745_2(unknown) = AliasedDefinition : # 745| mu745_3(unknown) = InitializeNonLocal : -# 745| mu745_4(unknown) = UnmodeledDefinition : -# 745| r745_5(glval) = InitializeThis : +# 745| r745_4(glval) = VariableAddress[#this] : +# 745| mu745_5(glval) = InitializeParameter[#this] : &:r745_4 +# 745| r745_6(glval) = Load : &:r745_4, ~m? +# 745| mu745_7(Base) = InitializeIndirection[#this] : &:r745_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 +#-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -# 745| r745_6(glval) = FieldAddress[base_s] : r745_5 -# 745| r745_7(glval) = FunctionAddress[String] : -# 745| v745_8(void) = Call : func:r745_7, this:r745_6 -# 745| mu745_9(unknown) = ^CallSideEffect : ~mu745_4 -# 745| mu745_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_6 -# 745| v745_11(void) = NoOp : -#-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 -# 745| v745_12(void) = ReturnVoid : -# 745| v745_13(void) = UnmodeledUse : mu* -# 745| v745_14(void) = AliasedUse : ~mu745_4 -# 745| v745_15(void) = ExitFunction : +# 745| r745_8(glval) = FieldAddress[base_s] : mu745_5 +# 745| r745_9(glval) = FunctionAddress[String] : +# 745| v745_10(void) = Call : func:r745_9, this:r745_8 +# 745| mu745_11(unknown) = ^CallSideEffect : ~m? +# 745| mu745_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_8 +# 745| v745_13(void) = NoOp : +# 745| v745_14(void) = ReturnIndirection[#this] : &:r745_6, ~m? +#-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 745| v745_15(void) = ReturnVoid : +# 745| v745_16(void) = AliasedUse : ~m? +# 745| v745_17(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 # 748| v748_1(void) = EnterFunction : # 748| mu748_2(unknown) = AliasedDefinition : # 748| mu748_3(unknown) = InitializeNonLocal : -# 748| mu748_4(unknown) = UnmodeledDefinition : -# 748| r748_5(glval) = InitializeThis : -# 748| r748_6(glval) = FieldAddress[base_s] : r748_5 -# 748| r748_7(glval) = FunctionAddress[String] : -# 748| v748_8(void) = Call : func:r748_7, this:r748_6 -# 748| mu748_9(unknown) = ^CallSideEffect : ~mu748_4 -# 748| mu748_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_6 +# 748| r748_4(glval) = VariableAddress[#this] : +# 748| mu748_5(glval) = InitializeParameter[#this] : &:r748_4 +# 748| r748_6(glval) = Load : &:r748_4, ~m? +# 748| mu748_7(Base) = InitializeIndirection[#this] : &:r748_6 +# 748| r748_8(glval) = FieldAddress[base_s] : mu748_5 +# 748| r748_9(glval) = FunctionAddress[String] : +# 748| v748_10(void) = Call : func:r748_9, this:r748_8 +# 748| mu748_11(unknown) = ^CallSideEffect : ~m? +# 748| mu748_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_8 # 749| v749_1(void) = NoOp : -# 748| v748_11(void) = ReturnVoid : -# 748| v748_12(void) = UnmodeledUse : mu* -# 748| v748_13(void) = AliasedUse : ~mu748_4 -# 748| v748_14(void) = ExitFunction : +# 748| v748_13(void) = ReturnIndirection[#this] : &:r748_6, ~m? +# 748| v748_14(void) = ReturnVoid : +# 748| v748_15(void) = AliasedUse : ~m? +# 748| v748_16(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 -# 750| v750_1(void) = EnterFunction : -# 750| mu750_2(unknown) = AliasedDefinition : -# 750| mu750_3(unknown) = InitializeNonLocal : -# 750| mu750_4(unknown) = UnmodeledDefinition : -# 750| r750_5(glval) = InitializeThis : -# 751| v751_1(void) = NoOp : -# 751| r751_2(glval) = FieldAddress[base_s] : r750_5 -# 751| r751_3(glval) = FunctionAddress[~String] : -# 751| v751_4(void) = Call : func:r751_3, this:r751_2 -# 751| mu751_5(unknown) = ^CallSideEffect : ~mu750_4 -# 750| v750_6(void) = ReturnVoid : -# 750| v750_7(void) = UnmodeledUse : mu* -# 750| v750_8(void) = AliasedUse : ~mu750_4 -# 750| v750_9(void) = ExitFunction : +# 750| v750_1(void) = EnterFunction : +# 750| mu750_2(unknown) = AliasedDefinition : +# 750| mu750_3(unknown) = InitializeNonLocal : +# 750| r750_4(glval) = VariableAddress[#this] : +# 750| mu750_5(glval) = InitializeParameter[#this] : &:r750_4 +# 750| r750_6(glval) = Load : &:r750_4, ~m? +# 750| mu750_7(Base) = InitializeIndirection[#this] : &:r750_6 +# 751| v751_1(void) = NoOp : +# 751| r751_2(glval) = FieldAddress[base_s] : mu750_5 +# 751| r751_3(glval) = FunctionAddress[~String] : +# 751| v751_4(void) = Call : func:r751_3, this:r751_2 +# 751| mu751_5(unknown) = ^CallSideEffect : ~m? +# 750| v750_8(void) = ReturnIndirection[#this] : &:r750_6, ~m? +# 750| v750_9(void) = ReturnVoid : +# 750| v750_10(void) = AliasedUse : ~m? +# 750| v750_11(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 # 754| v754_1(void) = EnterFunction : # 754| mu754_2(unknown) = AliasedDefinition : # 754| mu754_3(unknown) = InitializeNonLocal : -# 754| mu754_4(unknown) = UnmodeledDefinition : -# 754| r754_5(glval) = InitializeThis : +# 754| r754_4(glval) = VariableAddress[#this] : +# 754| mu754_5(glval) = InitializeParameter[#this] : &:r754_4 +# 754| r754_6(glval) = Load : &:r754_4, ~m? +# 754| mu754_7(Middle) = InitializeIndirection[#this] : &:r754_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Middle &) = Load : &:r0_1, ~mu754_4 +#-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Middle *) = CopyValue : r754_5 -#-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 -# 754| r754_6(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Middle &) = Load : &:r0_7, ~mu754_4 -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Middle *) = CopyValue : r0_9 -#-----| r0_11(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Base &) = CopyValue : r0_12 -# 754| r754_7(Base &) = Call : func:r754_6, this:r0_6, 0:r0_13 -# 754| mu754_8(unknown) = ^CallSideEffect : ~mu754_4 -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~mu754_4 -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~mu754_4 -#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r754_7 -#-----| r0_19(Middle *) = CopyValue : r754_5 -#-----| r0_20(glval) = FieldAddress[middle_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 -# 754| r754_9(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Middle &) = Load : &:r0_22, ~mu754_4 -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[middle_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 754| r754_10(String &) = Call : func:r754_9, this:r0_21, 0:r0_26 -# 754| mu754_11(unknown) = ^CallSideEffect : ~mu754_4 -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu754_4 -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~mu754_4 -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r754_10 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Middle *) = CopyValue : r754_5 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Middle &) = CopyValue : r0_34 -#-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu754_4 -# 754| r754_12(glval) = VariableAddress[#return] : -# 754| v754_13(void) = ReturnValue : &:r754_12, ~mu754_4 -# 754| v754_14(void) = UnmodeledUse : mu* -# 754| v754_15(void) = AliasedUse : ~mu754_4 -# 754| v754_16(void) = ExitFunction : +# 754| r754_8(glval) = VariableAddress[#this] : +# 754| r754_9(Middle *) = Load : &:r754_8, ~m? +#-----| r0_5(Base *) = ConvertToNonVirtualBase[Middle : Base] : r754_9 +# 754| r754_10(glval) = FunctionAddress[operator=] : +# 754| r754_11(glval) = VariableAddress[p#0] : +# 754| r754_12(Middle &) = Load : &:r754_11, ~m? +#-----| r0_6(glval) = CopyValue : r754_12 +# 754| r754_13(Middle *) = CopyValue : r0_6 +#-----| r0_7(Base *) = ConvertToNonVirtualBase[Middle : Base] : r754_13 +# 754| r754_14(glval) = CopyValue : r0_7 +#-----| r0_8(Base &) = CopyValue : r754_14 +# 754| r754_15(Base &) = Call : func:r754_10, this:r0_5, 0:r0_8 +# 754| mu754_16(unknown) = ^CallSideEffect : ~m? +#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? +#-----| mu0_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 +#-----| mu0_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_8 +#-----| r0_13(glval) = CopyValue : r754_15 +# 754| r754_17(glval) = VariableAddress[#this] : +# 754| r754_18(Middle *) = Load : &:r754_17, ~m? +# 754| r754_19(glval) = FieldAddress[middle_s] : r754_18 +# 754| r754_20(String *) = CopyValue : r754_19 +# 754| r754_21(glval) = FunctionAddress[operator=] : +# 754| r754_22(glval) = VariableAddress[p#0] : +# 754| r754_23(Middle &) = Load : &:r754_22, ~m? +#-----| r0_14(glval) = CopyValue : r754_23 +# 754| r754_24(glval) = FieldAddress[middle_s] : r0_14 +#-----| r0_15(String &) = CopyValue : r754_24 +# 754| r754_25(String &) = Call : func:r754_21, this:r754_20, 0:r0_15 +# 754| mu754_26(unknown) = ^CallSideEffect : ~m? +# 754| v754_27(void) = ^BufferReadSideEffect[-1] : &:r754_20, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_15, ~m? +# 754| mu754_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r754_20 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_15 +#-----| r0_18(glval) = CopyValue : r754_25 +#-----| r0_19(glval) = VariableAddress[#return] : +#-----| r0_20(glval) = VariableAddress[#this] : +#-----| r0_21(Middle *) = Load : &:r0_20, ~m? +#-----| r0_22(glval) = CopyValue : r0_21 +#-----| r0_23(Middle &) = CopyValue : r0_22 +#-----| mu0_24(Middle &) = Store : &:r0_19, r0_23 +# 754| v754_29(void) = ReturnIndirection[#this] : &:r754_6, ~m? +#-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 754| r754_30(glval) = VariableAddress[#return] : +# 754| v754_31(void) = ReturnValue : &:r754_30, ~m? +# 754| v754_32(void) = AliasedUse : ~m? +# 754| v754_33(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 # 757| v757_1(void) = EnterFunction : # 757| mu757_2(unknown) = AliasedDefinition : # 757| mu757_3(unknown) = InitializeNonLocal : -# 757| mu757_4(unknown) = UnmodeledDefinition : -# 757| r757_5(glval) = InitializeThis : -# 757| r757_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r757_5 -# 757| r757_7(glval) = FunctionAddress[Base] : -# 757| v757_8(void) = Call : func:r757_7, this:r757_6 -# 757| mu757_9(unknown) = ^CallSideEffect : ~mu757_4 -# 757| mu757_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_6 -# 757| r757_11(glval) = FieldAddress[middle_s] : r757_5 -# 757| r757_12(glval) = FunctionAddress[String] : -# 757| v757_13(void) = Call : func:r757_12, this:r757_11 -# 757| mu757_14(unknown) = ^CallSideEffect : ~mu757_4 -# 757| mu757_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_11 +# 757| r757_4(glval) = VariableAddress[#this] : +# 757| mu757_5(glval) = InitializeParameter[#this] : &:r757_4 +# 757| r757_6(glval) = Load : &:r757_4, ~m? +# 757| mu757_7(Middle) = InitializeIndirection[#this] : &:r757_6 +# 757| r757_8(glval) = ConvertToNonVirtualBase[Middle : Base] : mu757_5 +# 757| r757_9(glval) = FunctionAddress[Base] : +# 757| v757_10(void) = Call : func:r757_9, this:r757_8 +# 757| mu757_11(unknown) = ^CallSideEffect : ~m? +# 757| mu757_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_8 +# 757| r757_13(glval) = FieldAddress[middle_s] : mu757_5 +# 757| r757_14(glval) = FunctionAddress[String] : +# 757| v757_15(void) = Call : func:r757_14, this:r757_13 +# 757| mu757_16(unknown) = ^CallSideEffect : ~m? +# 757| mu757_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_13 # 758| v758_1(void) = NoOp : -# 757| v757_16(void) = ReturnVoid : -# 757| v757_17(void) = UnmodeledUse : mu* -# 757| v757_18(void) = AliasedUse : ~mu757_4 -# 757| v757_19(void) = ExitFunction : +# 757| v757_18(void) = ReturnIndirection[#this] : &:r757_6, ~m? +# 757| v757_19(void) = ReturnVoid : +# 757| v757_20(void) = AliasedUse : ~m? +# 757| v757_21(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 # 759| v759_1(void) = EnterFunction : # 759| mu759_2(unknown) = AliasedDefinition : # 759| mu759_3(unknown) = InitializeNonLocal : -# 759| mu759_4(unknown) = UnmodeledDefinition : -# 759| r759_5(glval) = InitializeThis : +# 759| r759_4(glval) = VariableAddress[#this] : +# 759| mu759_5(glval) = InitializeParameter[#this] : &:r759_4 +# 759| r759_6(glval) = Load : &:r759_4, ~m? +# 759| mu759_7(Middle) = InitializeIndirection[#this] : &:r759_6 # 760| v760_1(void) = NoOp : -# 760| r760_2(glval) = FieldAddress[middle_s] : r759_5 +# 760| r760_2(glval) = FieldAddress[middle_s] : mu759_5 # 760| r760_3(glval) = FunctionAddress[~String] : # 760| v760_4(void) = Call : func:r760_3, this:r760_2 -# 760| mu760_5(unknown) = ^CallSideEffect : ~mu759_4 -# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r759_5 +# 760| mu760_5(unknown) = ^CallSideEffect : ~m? +# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : mu759_5 # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 -# 760| mu760_9(unknown) = ^CallSideEffect : ~mu759_4 -# 759| v759_6(void) = ReturnVoid : -# 759| v759_7(void) = UnmodeledUse : mu* -# 759| v759_8(void) = AliasedUse : ~mu759_4 -# 759| v759_9(void) = ExitFunction : +# 760| mu760_9(unknown) = ^CallSideEffect : ~m? +# 759| v759_8(void) = ReturnIndirection[#this] : &:r759_6, ~m? +# 759| v759_9(void) = ReturnVoid : +# 759| v759_10(void) = AliasedUse : ~m? +# 759| v759_11(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 # 763| v763_1(void) = EnterFunction : # 763| mu763_2(unknown) = AliasedDefinition : # 763| mu763_3(unknown) = InitializeNonLocal : -# 763| mu763_4(unknown) = UnmodeledDefinition : -# 763| r763_5(glval) = InitializeThis : +# 763| r763_4(glval) = VariableAddress[#this] : +# 763| mu763_5(glval) = InitializeParameter[#this] : &:r763_4 +# 763| r763_6(glval) = Load : &:r763_4, ~m? +# 763| mu763_7(Derived) = InitializeIndirection[#this] : &:r763_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Derived &) = Load : &:r0_1, ~mu763_4 +#-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Derived *) = CopyValue : r763_5 -#-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 -# 763| r763_6(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Derived &) = Load : &:r0_7, ~mu763_4 -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Derived *) = CopyValue : r0_9 -#-----| r0_11(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Middle &) = CopyValue : r0_12 -# 763| r763_7(Middle &) = Call : func:r763_6, this:r0_6, 0:r0_13 -# 763| mu763_8(unknown) = ^CallSideEffect : ~mu763_4 -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~mu763_4 -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~mu763_4 -#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r763_7 -#-----| r0_19(Derived *) = CopyValue : r763_5 -#-----| r0_20(glval) = FieldAddress[derived_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 -# 763| r763_9(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Derived &) = Load : &:r0_22, ~mu763_4 -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[derived_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 763| r763_10(String &) = Call : func:r763_9, this:r0_21, 0:r0_26 -# 763| mu763_11(unknown) = ^CallSideEffect : ~mu763_4 -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu763_4 -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~mu763_4 -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r763_10 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Derived *) = CopyValue : r763_5 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Derived &) = CopyValue : r0_34 -#-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu763_4 -# 763| r763_12(glval) = VariableAddress[#return] : -# 763| v763_13(void) = ReturnValue : &:r763_12, ~mu763_4 -# 763| v763_14(void) = UnmodeledUse : mu* -# 763| v763_15(void) = AliasedUse : ~mu763_4 -# 763| v763_16(void) = ExitFunction : +# 763| r763_8(glval) = VariableAddress[#this] : +# 763| r763_9(Derived *) = Load : &:r763_8, ~m? +#-----| r0_5(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r763_9 +# 763| r763_10(glval) = FunctionAddress[operator=] : +# 763| r763_11(glval) = VariableAddress[p#0] : +# 763| r763_12(Derived &) = Load : &:r763_11, ~m? +#-----| r0_6(glval) = CopyValue : r763_12 +# 763| r763_13(Derived *) = CopyValue : r0_6 +#-----| r0_7(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r763_13 +# 763| r763_14(glval) = CopyValue : r0_7 +#-----| r0_8(Middle &) = CopyValue : r763_14 +# 763| r763_15(Middle &) = Call : func:r763_10, this:r0_5, 0:r0_8 +# 763| mu763_16(unknown) = ^CallSideEffect : ~m? +#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? +#-----| mu0_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 +#-----| mu0_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_8 +#-----| r0_13(glval) = CopyValue : r763_15 +# 763| r763_17(glval) = VariableAddress[#this] : +# 763| r763_18(Derived *) = Load : &:r763_17, ~m? +# 763| r763_19(glval) = FieldAddress[derived_s] : r763_18 +# 763| r763_20(String *) = CopyValue : r763_19 +# 763| r763_21(glval) = FunctionAddress[operator=] : +# 763| r763_22(glval) = VariableAddress[p#0] : +# 763| r763_23(Derived &) = Load : &:r763_22, ~m? +#-----| r0_14(glval) = CopyValue : r763_23 +# 763| r763_24(glval) = FieldAddress[derived_s] : r0_14 +#-----| r0_15(String &) = CopyValue : r763_24 +# 763| r763_25(String &) = Call : func:r763_21, this:r763_20, 0:r0_15 +# 763| mu763_26(unknown) = ^CallSideEffect : ~m? +# 763| v763_27(void) = ^BufferReadSideEffect[-1] : &:r763_20, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_15, ~m? +# 763| mu763_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r763_20 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_15 +#-----| r0_18(glval) = CopyValue : r763_25 +#-----| r0_19(glval) = VariableAddress[#return] : +#-----| r0_20(glval) = VariableAddress[#this] : +#-----| r0_21(Derived *) = Load : &:r0_20, ~m? +#-----| r0_22(glval) = CopyValue : r0_21 +#-----| r0_23(Derived &) = CopyValue : r0_22 +#-----| mu0_24(Derived &) = Store : &:r0_19, r0_23 +# 763| v763_29(void) = ReturnIndirection[#this] : &:r763_6, ~m? +#-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 763| r763_30(glval) = VariableAddress[#return] : +# 763| v763_31(void) = ReturnValue : &:r763_30, ~m? +# 763| v763_32(void) = AliasedUse : ~m? +# 763| v763_33(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 # 766| v766_1(void) = EnterFunction : # 766| mu766_2(unknown) = AliasedDefinition : # 766| mu766_3(unknown) = InitializeNonLocal : -# 766| mu766_4(unknown) = UnmodeledDefinition : -# 766| r766_5(glval) = InitializeThis : -# 766| r766_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r766_5 -# 766| r766_7(glval) = FunctionAddress[Middle] : -# 766| v766_8(void) = Call : func:r766_7, this:r766_6 -# 766| mu766_9(unknown) = ^CallSideEffect : ~mu766_4 -# 766| mu766_10(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_6 -# 766| r766_11(glval) = FieldAddress[derived_s] : r766_5 -# 766| r766_12(glval) = FunctionAddress[String] : -# 766| v766_13(void) = Call : func:r766_12, this:r766_11 -# 766| mu766_14(unknown) = ^CallSideEffect : ~mu766_4 -# 766| mu766_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_11 +# 766| r766_4(glval) = VariableAddress[#this] : +# 766| mu766_5(glval) = InitializeParameter[#this] : &:r766_4 +# 766| r766_6(glval) = Load : &:r766_4, ~m? +# 766| mu766_7(Derived) = InitializeIndirection[#this] : &:r766_6 +# 766| r766_8(glval) = ConvertToNonVirtualBase[Derived : Middle] : mu766_5 +# 766| r766_9(glval) = FunctionAddress[Middle] : +# 766| v766_10(void) = Call : func:r766_9, this:r766_8 +# 766| mu766_11(unknown) = ^CallSideEffect : ~m? +# 766| mu766_12(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_8 +# 766| r766_13(glval) = FieldAddress[derived_s] : mu766_5 +# 766| r766_14(glval) = FunctionAddress[String] : +# 766| v766_15(void) = Call : func:r766_14, this:r766_13 +# 766| mu766_16(unknown) = ^CallSideEffect : ~m? +# 766| mu766_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_13 # 767| v767_1(void) = NoOp : -# 766| v766_16(void) = ReturnVoid : -# 766| v766_17(void) = UnmodeledUse : mu* -# 766| v766_18(void) = AliasedUse : ~mu766_4 -# 766| v766_19(void) = ExitFunction : +# 766| v766_18(void) = ReturnIndirection[#this] : &:r766_6, ~m? +# 766| v766_19(void) = ReturnVoid : +# 766| v766_20(void) = AliasedUse : ~m? +# 766| v766_21(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 -# 768| v768_1(void) = EnterFunction : -# 768| mu768_2(unknown) = AliasedDefinition : -# 768| mu768_3(unknown) = InitializeNonLocal : -# 768| mu768_4(unknown) = UnmodeledDefinition : -# 768| r768_5(glval) = InitializeThis : -# 769| v769_1(void) = NoOp : -# 769| r769_2(glval) = FieldAddress[derived_s] : r768_5 -# 769| r769_3(glval) = FunctionAddress[~String] : -# 769| v769_4(void) = Call : func:r769_3, this:r769_2 -# 769| mu769_5(unknown) = ^CallSideEffect : ~mu768_4 -# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r768_5 -# 769| r769_7(glval) = FunctionAddress[~Middle] : -# 769| v769_8(void) = Call : func:r769_7, this:r769_6 -# 769| mu769_9(unknown) = ^CallSideEffect : ~mu768_4 -# 768| v768_6(void) = ReturnVoid : -# 768| v768_7(void) = UnmodeledUse : mu* -# 768| v768_8(void) = AliasedUse : ~mu768_4 -# 768| v768_9(void) = ExitFunction : +# 768| v768_1(void) = EnterFunction : +# 768| mu768_2(unknown) = AliasedDefinition : +# 768| mu768_3(unknown) = InitializeNonLocal : +# 768| r768_4(glval) = VariableAddress[#this] : +# 768| mu768_5(glval) = InitializeParameter[#this] : &:r768_4 +# 768| r768_6(glval) = Load : &:r768_4, ~m? +# 768| mu768_7(Derived) = InitializeIndirection[#this] : &:r768_6 +# 769| v769_1(void) = NoOp : +# 769| r769_2(glval) = FieldAddress[derived_s] : mu768_5 +# 769| r769_3(glval) = FunctionAddress[~String] : +# 769| v769_4(void) = Call : func:r769_3, this:r769_2 +# 769| mu769_5(unknown) = ^CallSideEffect : ~m? +# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : mu768_5 +# 769| r769_7(glval) = FunctionAddress[~Middle] : +# 769| v769_8(void) = Call : func:r769_7, this:r769_6 +# 769| mu769_9(unknown) = ^CallSideEffect : ~m? +# 768| v768_8(void) = ReturnIndirection[#this] : &:r768_6, ~m? +# 768| v768_9(void) = ReturnVoid : +# 768| v768_10(void) = AliasedUse : ~m? +# 768| v768_11(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 -# 775| v775_1(void) = EnterFunction : -# 775| mu775_2(unknown) = AliasedDefinition : -# 775| mu775_3(unknown) = InitializeNonLocal : -# 775| mu775_4(unknown) = UnmodeledDefinition : -# 775| r775_5(glval) = InitializeThis : -# 775| r775_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r775_5 -# 775| r775_7(glval) = FunctionAddress[Base] : -# 775| v775_8(void) = Call : func:r775_7, this:r775_6 -# 775| mu775_9(unknown) = ^CallSideEffect : ~mu775_4 -# 775| mu775_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_6 -# 775| r775_11(glval) = FieldAddress[middlevb1_s] : r775_5 -# 775| r775_12(glval) = FunctionAddress[String] : -# 775| v775_13(void) = Call : func:r775_12, this:r775_11 -# 775| mu775_14(unknown) = ^CallSideEffect : ~mu775_4 -# 775| mu775_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_11 -# 776| v776_1(void) = NoOp : -# 775| v775_16(void) = ReturnVoid : -# 775| v775_17(void) = UnmodeledUse : mu* -# 775| v775_18(void) = AliasedUse : ~mu775_4 -# 775| v775_19(void) = ExitFunction : +# 775| v775_1(void) = EnterFunction : +# 775| mu775_2(unknown) = AliasedDefinition : +# 775| mu775_3(unknown) = InitializeNonLocal : +# 775| r775_4(glval) = VariableAddress[#this] : +# 775| mu775_5(glval) = InitializeParameter[#this] : &:r775_4 +# 775| r775_6(glval) = Load : &:r775_4, ~m? +# 775| mu775_7(MiddleVB1) = InitializeIndirection[#this] : &:r775_6 +# 775| r775_8(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : mu775_5 +# 775| r775_9(glval) = FunctionAddress[Base] : +# 775| v775_10(void) = Call : func:r775_9, this:r775_8 +# 775| mu775_11(unknown) = ^CallSideEffect : ~m? +# 775| mu775_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_8 +# 775| r775_13(glval) = FieldAddress[middlevb1_s] : mu775_5 +# 775| r775_14(glval) = FunctionAddress[String] : +# 775| v775_15(void) = Call : func:r775_14, this:r775_13 +# 775| mu775_16(unknown) = ^CallSideEffect : ~m? +# 775| mu775_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_13 +# 776| v776_1(void) = NoOp : +# 775| v775_18(void) = ReturnIndirection[#this] : &:r775_6, ~m? +# 775| v775_19(void) = ReturnVoid : +# 775| v775_20(void) = AliasedUse : ~m? +# 775| v775_21(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 -# 777| v777_1(void) = EnterFunction : -# 777| mu777_2(unknown) = AliasedDefinition : -# 777| mu777_3(unknown) = InitializeNonLocal : -# 777| mu777_4(unknown) = UnmodeledDefinition : -# 777| r777_5(glval) = InitializeThis : -# 778| v778_1(void) = NoOp : -# 778| r778_2(glval) = FieldAddress[middlevb1_s] : r777_5 -# 778| r778_3(glval) = FunctionAddress[~String] : -# 778| v778_4(void) = Call : func:r778_3, this:r778_2 -# 778| mu778_5(unknown) = ^CallSideEffect : ~mu777_4 -# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r777_5 -# 778| r778_7(glval) = FunctionAddress[~Base] : -# 778| v778_8(void) = Call : func:r778_7, this:r778_6 -# 778| mu778_9(unknown) = ^CallSideEffect : ~mu777_4 -# 777| v777_6(void) = ReturnVoid : -# 777| v777_7(void) = UnmodeledUse : mu* -# 777| v777_8(void) = AliasedUse : ~mu777_4 -# 777| v777_9(void) = ExitFunction : +# 777| v777_1(void) = EnterFunction : +# 777| mu777_2(unknown) = AliasedDefinition : +# 777| mu777_3(unknown) = InitializeNonLocal : +# 777| r777_4(glval) = VariableAddress[#this] : +# 777| mu777_5(glval) = InitializeParameter[#this] : &:r777_4 +# 777| r777_6(glval) = Load : &:r777_4, ~m? +# 777| mu777_7(MiddleVB1) = InitializeIndirection[#this] : &:r777_6 +# 778| v778_1(void) = NoOp : +# 778| r778_2(glval) = FieldAddress[middlevb1_s] : mu777_5 +# 778| r778_3(glval) = FunctionAddress[~String] : +# 778| v778_4(void) = Call : func:r778_3, this:r778_2 +# 778| mu778_5(unknown) = ^CallSideEffect : ~m? +# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : mu777_5 +# 778| r778_7(glval) = FunctionAddress[~Base] : +# 778| v778_8(void) = Call : func:r778_7, this:r778_6 +# 778| mu778_9(unknown) = ^CallSideEffect : ~m? +# 777| v777_8(void) = ReturnIndirection[#this] : &:r777_6, ~m? +# 777| v777_9(void) = ReturnVoid : +# 777| v777_10(void) = AliasedUse : ~m? +# 777| v777_11(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 -# 784| v784_1(void) = EnterFunction : -# 784| mu784_2(unknown) = AliasedDefinition : -# 784| mu784_3(unknown) = InitializeNonLocal : -# 784| mu784_4(unknown) = UnmodeledDefinition : -# 784| r784_5(glval) = InitializeThis : -# 784| r784_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r784_5 -# 784| r784_7(glval) = FunctionAddress[Base] : -# 784| v784_8(void) = Call : func:r784_7, this:r784_6 -# 784| mu784_9(unknown) = ^CallSideEffect : ~mu784_4 -# 784| mu784_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_6 -# 784| r784_11(glval) = FieldAddress[middlevb2_s] : r784_5 -# 784| r784_12(glval) = FunctionAddress[String] : -# 784| v784_13(void) = Call : func:r784_12, this:r784_11 -# 784| mu784_14(unknown) = ^CallSideEffect : ~mu784_4 -# 784| mu784_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_11 -# 785| v785_1(void) = NoOp : -# 784| v784_16(void) = ReturnVoid : -# 784| v784_17(void) = UnmodeledUse : mu* -# 784| v784_18(void) = AliasedUse : ~mu784_4 -# 784| v784_19(void) = ExitFunction : +# 784| v784_1(void) = EnterFunction : +# 784| mu784_2(unknown) = AliasedDefinition : +# 784| mu784_3(unknown) = InitializeNonLocal : +# 784| r784_4(glval) = VariableAddress[#this] : +# 784| mu784_5(glval) = InitializeParameter[#this] : &:r784_4 +# 784| r784_6(glval) = Load : &:r784_4, ~m? +# 784| mu784_7(MiddleVB2) = InitializeIndirection[#this] : &:r784_6 +# 784| r784_8(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : mu784_5 +# 784| r784_9(glval) = FunctionAddress[Base] : +# 784| v784_10(void) = Call : func:r784_9, this:r784_8 +# 784| mu784_11(unknown) = ^CallSideEffect : ~m? +# 784| mu784_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_8 +# 784| r784_13(glval) = FieldAddress[middlevb2_s] : mu784_5 +# 784| r784_14(glval) = FunctionAddress[String] : +# 784| v784_15(void) = Call : func:r784_14, this:r784_13 +# 784| mu784_16(unknown) = ^CallSideEffect : ~m? +# 784| mu784_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_13 +# 785| v785_1(void) = NoOp : +# 784| v784_18(void) = ReturnIndirection[#this] : &:r784_6, ~m? +# 784| v784_19(void) = ReturnVoid : +# 784| v784_20(void) = AliasedUse : ~m? +# 784| v784_21(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 -# 786| v786_1(void) = EnterFunction : -# 786| mu786_2(unknown) = AliasedDefinition : -# 786| mu786_3(unknown) = InitializeNonLocal : -# 786| mu786_4(unknown) = UnmodeledDefinition : -# 786| r786_5(glval) = InitializeThis : -# 787| v787_1(void) = NoOp : -# 787| r787_2(glval) = FieldAddress[middlevb2_s] : r786_5 -# 787| r787_3(glval) = FunctionAddress[~String] : -# 787| v787_4(void) = Call : func:r787_3, this:r787_2 -# 787| mu787_5(unknown) = ^CallSideEffect : ~mu786_4 -# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r786_5 -# 787| r787_7(glval) = FunctionAddress[~Base] : -# 787| v787_8(void) = Call : func:r787_7, this:r787_6 -# 787| mu787_9(unknown) = ^CallSideEffect : ~mu786_4 -# 786| v786_6(void) = ReturnVoid : -# 786| v786_7(void) = UnmodeledUse : mu* -# 786| v786_8(void) = AliasedUse : ~mu786_4 -# 786| v786_9(void) = ExitFunction : +# 786| v786_1(void) = EnterFunction : +# 786| mu786_2(unknown) = AliasedDefinition : +# 786| mu786_3(unknown) = InitializeNonLocal : +# 786| r786_4(glval) = VariableAddress[#this] : +# 786| mu786_5(glval) = InitializeParameter[#this] : &:r786_4 +# 786| r786_6(glval) = Load : &:r786_4, ~m? +# 786| mu786_7(MiddleVB2) = InitializeIndirection[#this] : &:r786_6 +# 787| v787_1(void) = NoOp : +# 787| r787_2(glval) = FieldAddress[middlevb2_s] : mu786_5 +# 787| r787_3(glval) = FunctionAddress[~String] : +# 787| v787_4(void) = Call : func:r787_3, this:r787_2 +# 787| mu787_5(unknown) = ^CallSideEffect : ~m? +# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : mu786_5 +# 787| r787_7(glval) = FunctionAddress[~Base] : +# 787| v787_8(void) = Call : func:r787_7, this:r787_6 +# 787| mu787_9(unknown) = ^CallSideEffect : ~m? +# 786| v786_8(void) = ReturnIndirection[#this] : &:r786_6, ~m? +# 786| v786_9(void) = ReturnVoid : +# 786| v786_10(void) = AliasedUse : ~m? +# 786| v786_11(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 # 793| v793_1(void) = EnterFunction : # 793| mu793_2(unknown) = AliasedDefinition : # 793| mu793_3(unknown) = InitializeNonLocal : -# 793| mu793_4(unknown) = UnmodeledDefinition : -# 793| r793_5(glval) = InitializeThis : -# 793| r793_6(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r793_5 -# 793| r793_7(glval) = FunctionAddress[Base] : -# 793| v793_8(void) = Call : func:r793_7, this:r793_6 -# 793| mu793_9(unknown) = ^CallSideEffect : ~mu793_4 -# 793| mu793_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_6 -# 793| r793_11(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r793_5 -# 793| r793_12(glval) = FunctionAddress[MiddleVB1] : -# 793| v793_13(void) = Call : func:r793_12, this:r793_11 -# 793| mu793_14(unknown) = ^CallSideEffect : ~mu793_4 -# 793| mu793_15(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_11 -# 793| r793_16(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r793_5 -# 793| r793_17(glval) = FunctionAddress[MiddleVB2] : -# 793| v793_18(void) = Call : func:r793_17, this:r793_16 -# 793| mu793_19(unknown) = ^CallSideEffect : ~mu793_4 -# 793| mu793_20(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_16 -# 793| r793_21(glval) = FieldAddress[derivedvb_s] : r793_5 -# 793| r793_22(glval) = FunctionAddress[String] : -# 793| v793_23(void) = Call : func:r793_22, this:r793_21 -# 793| mu793_24(unknown) = ^CallSideEffect : ~mu793_4 -# 793| mu793_25(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_21 +# 793| r793_4(glval) = VariableAddress[#this] : +# 793| mu793_5(glval) = InitializeParameter[#this] : &:r793_4 +# 793| r793_6(glval) = Load : &:r793_4, ~m? +# 793| mu793_7(DerivedVB) = InitializeIndirection[#this] : &:r793_6 +# 793| r793_8(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : mu793_5 +# 793| r793_9(glval) = FunctionAddress[Base] : +# 793| v793_10(void) = Call : func:r793_9, this:r793_8 +# 793| mu793_11(unknown) = ^CallSideEffect : ~m? +# 793| mu793_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_8 +# 793| r793_13(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : mu793_5 +# 793| r793_14(glval) = FunctionAddress[MiddleVB1] : +# 793| v793_15(void) = Call : func:r793_14, this:r793_13 +# 793| mu793_16(unknown) = ^CallSideEffect : ~m? +# 793| mu793_17(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_13 +# 793| r793_18(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : mu793_5 +# 793| r793_19(glval) = FunctionAddress[MiddleVB2] : +# 793| v793_20(void) = Call : func:r793_19, this:r793_18 +# 793| mu793_21(unknown) = ^CallSideEffect : ~m? +# 793| mu793_22(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_18 +# 793| r793_23(glval) = FieldAddress[derivedvb_s] : mu793_5 +# 793| r793_24(glval) = FunctionAddress[String] : +# 793| v793_25(void) = Call : func:r793_24, this:r793_23 +# 793| mu793_26(unknown) = ^CallSideEffect : ~m? +# 793| mu793_27(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_23 # 794| v794_1(void) = NoOp : -# 793| v793_26(void) = ReturnVoid : -# 793| v793_27(void) = UnmodeledUse : mu* -# 793| v793_28(void) = AliasedUse : ~mu793_4 -# 793| v793_29(void) = ExitFunction : +# 793| v793_28(void) = ReturnIndirection[#this] : &:r793_6, ~m? +# 793| v793_29(void) = ReturnVoid : +# 793| v793_30(void) = AliasedUse : ~m? +# 793| v793_31(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 # 795| v795_1(void) = EnterFunction : # 795| mu795_2(unknown) = AliasedDefinition : # 795| mu795_3(unknown) = InitializeNonLocal : -# 795| mu795_4(unknown) = UnmodeledDefinition : -# 795| r795_5(glval) = InitializeThis : +# 795| r795_4(glval) = VariableAddress[#this] : +# 795| mu795_5(glval) = InitializeParameter[#this] : &:r795_4 +# 795| r795_6(glval) = Load : &:r795_4, ~m? +# 795| mu795_7(DerivedVB) = InitializeIndirection[#this] : &:r795_6 # 796| v796_1(void) = NoOp : -# 796| r796_2(glval) = FieldAddress[derivedvb_s] : r795_5 +# 796| r796_2(glval) = FieldAddress[derivedvb_s] : mu795_5 # 796| r796_3(glval) = FunctionAddress[~String] : # 796| v796_4(void) = Call : func:r796_3, this:r796_2 -# 796| mu796_5(unknown) = ^CallSideEffect : ~mu795_4 -# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r795_5 +# 796| mu796_5(unknown) = ^CallSideEffect : ~m? +# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : mu795_5 # 796| r796_7(glval) = FunctionAddress[~MiddleVB2] : # 796| v796_8(void) = Call : func:r796_7, this:r796_6 -# 796| mu796_9(unknown) = ^CallSideEffect : ~mu795_4 -# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r795_5 +# 796| mu796_9(unknown) = ^CallSideEffect : ~m? +# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : mu795_5 # 796| r796_11(glval) = FunctionAddress[~MiddleVB1] : # 796| v796_12(void) = Call : func:r796_11, this:r796_10 -# 796| mu796_13(unknown) = ^CallSideEffect : ~mu795_4 -# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r795_5 +# 796| mu796_13(unknown) = ^CallSideEffect : ~m? +# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : mu795_5 # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 -# 796| mu796_17(unknown) = ^CallSideEffect : ~mu795_4 -# 795| v795_6(void) = ReturnVoid : -# 795| v795_7(void) = UnmodeledUse : mu* -# 795| v795_8(void) = AliasedUse : ~mu795_4 -# 795| v795_9(void) = ExitFunction : +# 796| mu796_17(unknown) = ^CallSideEffect : ~m? +# 795| v795_8(void) = ReturnIndirection[#this] : &:r795_6, ~m? +# 795| v795_9(void) = ReturnVoid : +# 795| v795_10(void) = AliasedUse : ~m? +# 795| v795_11(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 # 799| v799_1(void) = EnterFunction : # 799| mu799_2(unknown) = AliasedDefinition : # 799| mu799_3(unknown) = InitializeNonLocal : -# 799| mu799_4(unknown) = UnmodeledDefinition : # 800| r800_1(glval) = VariableAddress[b] : # 800| mu800_2(Base) = Uninitialized[b] : &:r800_1 # 800| r800_3(glval) = FunctionAddress[Base] : # 800| v800_4(void) = Call : func:r800_3, this:r800_1 -# 800| mu800_5(unknown) = ^CallSideEffect : ~mu799_4 +# 800| mu800_5(unknown) = ^CallSideEffect : ~m? # 800| mu800_6(Base) = ^IndirectMayWriteSideEffect[-1] : &:r800_1 # 801| r801_1(glval) = VariableAddress[m] : # 801| mu801_2(Middle) = Uninitialized[m] : &:r801_1 # 801| r801_3(glval) = FunctionAddress[Middle] : # 801| v801_4(void) = Call : func:r801_3, this:r801_1 -# 801| mu801_5(unknown) = ^CallSideEffect : ~mu799_4 +# 801| mu801_5(unknown) = ^CallSideEffect : ~m? # 801| mu801_6(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r801_1 # 802| r802_1(glval) = VariableAddress[d] : # 802| mu802_2(Derived) = Uninitialized[d] : &:r802_1 # 802| r802_3(glval) = FunctionAddress[Derived] : # 802| v802_4(void) = Call : func:r802_3, this:r802_1 -# 802| mu802_5(unknown) = ^CallSideEffect : ~mu799_4 +# 802| mu802_5(unknown) = ^CallSideEffect : ~m? # 802| mu802_6(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r802_1 # 804| r804_1(glval) = VariableAddress[pb] : # 804| r804_2(glval) = VariableAddress[b] : @@ -4609,9 +4514,9 @@ ir.cpp: # 808| r808_4(glval) = ConvertToNonVirtualBase[Middle : Base] : r808_3 # 808| r808_5(Base &) = CopyValue : r808_4 # 808| r808_6(Base &) = Call : func:r808_2, this:r808_1, 0:r808_5 -# 808| mu808_7(unknown) = ^CallSideEffect : ~mu799_4 -# 808| v808_8(void) = ^BufferReadSideEffect[-1] : &:r808_1, ~mu799_4 -# 808| v808_9(void) = ^BufferReadSideEffect[0] : &:r808_5, ~mu799_4 +# 808| mu808_7(unknown) = ^CallSideEffect : ~m? +# 808| v808_8(void) = ^BufferReadSideEffect[-1] : &:r808_1, ~m? +# 808| v808_9(void) = ^BufferReadSideEffect[0] : &:r808_5, ~m? # 808| mu808_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r808_1 # 808| mu808_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r808_5 # 808| r808_12(glval) = CopyValue : r808_6 @@ -4622,16 +4527,16 @@ ir.cpp: # 809| r809_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r809_4 # 809| r809_6(Base &) = CopyValue : r809_5 # 809| v809_7(void) = Call : func:r809_3, 0:r809_6 -# 809| mu809_8(unknown) = ^CallSideEffect : ~mu799_4 +# 809| mu809_8(unknown) = ^CallSideEffect : ~m? # 809| mu809_9(Base) = ^IndirectMayWriteSideEffect[-1] : -# 809| v809_10(void) = ^BufferReadSideEffect[0] : &:r809_6, ~mu799_4 +# 809| v809_10(void) = ^BufferReadSideEffect[0] : &:r809_6, ~m? # 809| mu809_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r809_6 # 809| r809_12(glval) = Convert : v809_7 # 809| r809_13(Base &) = CopyValue : r809_12 # 809| r809_14(Base &) = Call : func:r809_2, this:r809_1, 0:r809_13 -# 809| mu809_15(unknown) = ^CallSideEffect : ~mu799_4 -# 809| v809_16(void) = ^BufferReadSideEffect[-1] : &:r809_1, ~mu799_4 -# 809| v809_17(void) = ^BufferReadSideEffect[0] : &:r809_13, ~mu799_4 +# 809| mu809_15(unknown) = ^CallSideEffect : ~m? +# 809| v809_16(void) = ^BufferReadSideEffect[-1] : &:r809_1, ~m? +# 809| v809_17(void) = ^BufferReadSideEffect[0] : &:r809_13, ~m? # 809| mu809_18(Base) = ^IndirectMayWriteSideEffect[-1] : &:r809_1 # 809| mu809_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r809_13 # 809| r809_20(glval) = CopyValue : r809_14 @@ -4642,36 +4547,36 @@ ir.cpp: # 810| r810_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r810_4 # 810| r810_6(Base &) = CopyValue : r810_5 # 810| v810_7(void) = Call : func:r810_3, 0:r810_6 -# 810| mu810_8(unknown) = ^CallSideEffect : ~mu799_4 +# 810| mu810_8(unknown) = ^CallSideEffect : ~m? # 810| mu810_9(Base) = ^IndirectMayWriteSideEffect[-1] : -# 810| v810_10(void) = ^BufferReadSideEffect[0] : &:r810_6, ~mu799_4 +# 810| v810_10(void) = ^BufferReadSideEffect[0] : &:r810_6, ~m? # 810| mu810_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r810_6 # 810| r810_12(glval) = Convert : v810_7 # 810| r810_13(Base &) = CopyValue : r810_12 # 810| r810_14(Base &) = Call : func:r810_2, this:r810_1, 0:r810_13 -# 810| mu810_15(unknown) = ^CallSideEffect : ~mu799_4 -# 810| v810_16(void) = ^BufferReadSideEffect[-1] : &:r810_1, ~mu799_4 -# 810| v810_17(void) = ^BufferReadSideEffect[0] : &:r810_13, ~mu799_4 +# 810| mu810_15(unknown) = ^CallSideEffect : ~m? +# 810| v810_16(void) = ^BufferReadSideEffect[-1] : &:r810_1, ~m? +# 810| v810_17(void) = ^BufferReadSideEffect[0] : &:r810_13, ~m? # 810| mu810_18(Base) = ^IndirectMayWriteSideEffect[-1] : &:r810_1 # 810| mu810_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r810_13 # 810| r810_20(glval) = CopyValue : r810_14 # 811| r811_1(glval) = VariableAddress[pm] : -# 811| r811_2(Middle *) = Load : &:r811_1, ~mu799_4 +# 811| r811_2(Middle *) = Load : &:r811_1, ~m? # 811| r811_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r811_2 # 811| r811_4(glval) = VariableAddress[pb] : # 811| mu811_5(Base *) = Store : &:r811_4, r811_3 # 812| r812_1(glval) = VariableAddress[pm] : -# 812| r812_2(Middle *) = Load : &:r812_1, ~mu799_4 +# 812| r812_2(Middle *) = Load : &:r812_1, ~m? # 812| r812_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r812_2 # 812| r812_4(glval) = VariableAddress[pb] : # 812| mu812_5(Base *) = Store : &:r812_4, r812_3 # 813| r813_1(glval) = VariableAddress[pm] : -# 813| r813_2(Middle *) = Load : &:r813_1, ~mu799_4 +# 813| r813_2(Middle *) = Load : &:r813_1, ~m? # 813| r813_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r813_2 # 813| r813_4(glval) = VariableAddress[pb] : # 813| mu813_5(Base *) = Store : &:r813_4, r813_3 # 814| r814_1(glval) = VariableAddress[pm] : -# 814| r814_2(Middle *) = Load : &:r814_1, ~mu799_4 +# 814| r814_2(Middle *) = Load : &:r814_1, ~m? # 814| r814_3(Base *) = Convert : r814_2 # 814| r814_4(glval) = VariableAddress[pb] : # 814| mu814_5(Base *) = Store : &:r814_4, r814_3 @@ -4682,9 +4587,9 @@ ir.cpp: # 816| r816_5(glval) = Convert : r816_4 # 816| r816_6(Middle &) = CopyValue : r816_5 # 816| r816_7(Middle &) = Call : func:r816_2, this:r816_1, 0:r816_6 -# 816| mu816_8(unknown) = ^CallSideEffect : ~mu799_4 -# 816| v816_9(void) = ^BufferReadSideEffect[-1] : &:r816_1, ~mu799_4 -# 816| v816_10(void) = ^BufferReadSideEffect[0] : &:r816_6, ~mu799_4 +# 816| mu816_8(unknown) = ^CallSideEffect : ~m? +# 816| v816_9(void) = ^BufferReadSideEffect[-1] : &:r816_1, ~m? +# 816| v816_10(void) = ^BufferReadSideEffect[0] : &:r816_6, ~m? # 816| mu816_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r816_1 # 816| mu816_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r816_6 # 816| r816_13(glval) = CopyValue : r816_7 @@ -4695,24 +4600,24 @@ ir.cpp: # 817| r817_5(glval) = Convert : r817_4 # 817| r817_6(Middle &) = CopyValue : r817_5 # 817| r817_7(Middle &) = Call : func:r817_2, this:r817_1, 0:r817_6 -# 817| mu817_8(unknown) = ^CallSideEffect : ~mu799_4 -# 817| v817_9(void) = ^BufferReadSideEffect[-1] : &:r817_1, ~mu799_4 -# 817| v817_10(void) = ^BufferReadSideEffect[0] : &:r817_6, ~mu799_4 +# 817| mu817_8(unknown) = ^CallSideEffect : ~m? +# 817| v817_9(void) = ^BufferReadSideEffect[-1] : &:r817_1, ~m? +# 817| v817_10(void) = ^BufferReadSideEffect[0] : &:r817_6, ~m? # 817| mu817_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r817_1 # 817| mu817_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r817_6 # 817| r817_13(glval) = CopyValue : r817_7 # 818| r818_1(glval) = VariableAddress[pb] : -# 818| r818_2(Base *) = Load : &:r818_1, ~mu799_4 +# 818| r818_2(Base *) = Load : &:r818_1, ~m? # 818| r818_3(Middle *) = ConvertToDerived[Middle : Base] : r818_2 # 818| r818_4(glval) = VariableAddress[pm] : # 818| mu818_5(Middle *) = Store : &:r818_4, r818_3 # 819| r819_1(glval) = VariableAddress[pb] : -# 819| r819_2(Base *) = Load : &:r819_1, ~mu799_4 +# 819| r819_2(Base *) = Load : &:r819_1, ~m? # 819| r819_3(Middle *) = ConvertToDerived[Middle : Base] : r819_2 # 819| r819_4(glval) = VariableAddress[pm] : # 819| mu819_5(Middle *) = Store : &:r819_4, r819_3 # 820| r820_1(glval) = VariableAddress[pb] : -# 820| r820_2(Base *) = Load : &:r820_1, ~mu799_4 +# 820| r820_2(Base *) = Load : &:r820_1, ~m? # 820| r820_3(Middle *) = Convert : r820_2 # 820| r820_4(glval) = VariableAddress[pm] : # 820| mu820_5(Middle *) = Store : &:r820_4, r820_3 @@ -4723,9 +4628,9 @@ ir.cpp: # 822| r822_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r822_4 # 822| r822_6(Base &) = CopyValue : r822_5 # 822| r822_7(Base &) = Call : func:r822_2, this:r822_1, 0:r822_6 -# 822| mu822_8(unknown) = ^CallSideEffect : ~mu799_4 -# 822| v822_9(void) = ^BufferReadSideEffect[-1] : &:r822_1, ~mu799_4 -# 822| v822_10(void) = ^BufferReadSideEffect[0] : &:r822_6, ~mu799_4 +# 822| mu822_8(unknown) = ^CallSideEffect : ~m? +# 822| v822_9(void) = ^BufferReadSideEffect[-1] : &:r822_1, ~m? +# 822| v822_10(void) = ^BufferReadSideEffect[0] : &:r822_6, ~m? # 822| mu822_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r822_1 # 822| mu822_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r822_6 # 822| r822_13(glval) = CopyValue : r822_7 @@ -4737,16 +4642,16 @@ ir.cpp: # 823| r823_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r823_5 # 823| r823_7(Base &) = CopyValue : r823_6 # 823| v823_8(void) = Call : func:r823_3, 0:r823_7 -# 823| mu823_9(unknown) = ^CallSideEffect : ~mu799_4 +# 823| mu823_9(unknown) = ^CallSideEffect : ~m? # 823| mu823_10(Base) = ^IndirectMayWriteSideEffect[-1] : -# 823| v823_11(void) = ^BufferReadSideEffect[0] : &:r823_7, ~mu799_4 +# 823| v823_11(void) = ^BufferReadSideEffect[0] : &:r823_7, ~m? # 823| mu823_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r823_7 # 823| r823_13(glval) = Convert : v823_8 # 823| r823_14(Base &) = CopyValue : r823_13 # 823| r823_15(Base &) = Call : func:r823_2, this:r823_1, 0:r823_14 -# 823| mu823_16(unknown) = ^CallSideEffect : ~mu799_4 -# 823| v823_17(void) = ^BufferReadSideEffect[-1] : &:r823_1, ~mu799_4 -# 823| v823_18(void) = ^BufferReadSideEffect[0] : &:r823_14, ~mu799_4 +# 823| mu823_16(unknown) = ^CallSideEffect : ~m? +# 823| v823_17(void) = ^BufferReadSideEffect[-1] : &:r823_1, ~m? +# 823| v823_18(void) = ^BufferReadSideEffect[0] : &:r823_14, ~m? # 823| mu823_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r823_1 # 823| mu823_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r823_14 # 823| r823_21(glval) = CopyValue : r823_15 @@ -4758,39 +4663,39 @@ ir.cpp: # 824| r824_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r824_5 # 824| r824_7(Base &) = CopyValue : r824_6 # 824| v824_8(void) = Call : func:r824_3, 0:r824_7 -# 824| mu824_9(unknown) = ^CallSideEffect : ~mu799_4 +# 824| mu824_9(unknown) = ^CallSideEffect : ~m? # 824| mu824_10(Base) = ^IndirectMayWriteSideEffect[-1] : -# 824| v824_11(void) = ^BufferReadSideEffect[0] : &:r824_7, ~mu799_4 +# 824| v824_11(void) = ^BufferReadSideEffect[0] : &:r824_7, ~m? # 824| mu824_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r824_7 # 824| r824_13(glval) = Convert : v824_8 # 824| r824_14(Base &) = CopyValue : r824_13 # 824| r824_15(Base &) = Call : func:r824_2, this:r824_1, 0:r824_14 -# 824| mu824_16(unknown) = ^CallSideEffect : ~mu799_4 -# 824| v824_17(void) = ^BufferReadSideEffect[-1] : &:r824_1, ~mu799_4 -# 824| v824_18(void) = ^BufferReadSideEffect[0] : &:r824_14, ~mu799_4 +# 824| mu824_16(unknown) = ^CallSideEffect : ~m? +# 824| v824_17(void) = ^BufferReadSideEffect[-1] : &:r824_1, ~m? +# 824| v824_18(void) = ^BufferReadSideEffect[0] : &:r824_14, ~m? # 824| mu824_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r824_1 # 824| mu824_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r824_14 # 824| r824_21(glval) = CopyValue : r824_15 # 825| r825_1(glval) = VariableAddress[pd] : -# 825| r825_2(Derived *) = Load : &:r825_1, ~mu799_4 +# 825| r825_2(Derived *) = Load : &:r825_1, ~m? # 825| r825_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r825_2 # 825| r825_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r825_3 # 825| r825_5(glval) = VariableAddress[pb] : # 825| mu825_6(Base *) = Store : &:r825_5, r825_4 # 826| r826_1(glval) = VariableAddress[pd] : -# 826| r826_2(Derived *) = Load : &:r826_1, ~mu799_4 +# 826| r826_2(Derived *) = Load : &:r826_1, ~m? # 826| r826_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r826_2 # 826| r826_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r826_3 # 826| r826_5(glval) = VariableAddress[pb] : # 826| mu826_6(Base *) = Store : &:r826_5, r826_4 # 827| r827_1(glval) = VariableAddress[pd] : -# 827| r827_2(Derived *) = Load : &:r827_1, ~mu799_4 +# 827| r827_2(Derived *) = Load : &:r827_1, ~m? # 827| r827_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r827_2 # 827| r827_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r827_3 # 827| r827_5(glval) = VariableAddress[pb] : # 827| mu827_6(Base *) = Store : &:r827_5, r827_4 # 828| r828_1(glval) = VariableAddress[pd] : -# 828| r828_2(Derived *) = Load : &:r828_1, ~mu799_4 +# 828| r828_2(Derived *) = Load : &:r828_1, ~m? # 828| r828_3(Base *) = Convert : r828_2 # 828| r828_4(glval) = VariableAddress[pb] : # 828| mu828_5(Base *) = Store : &:r828_4, r828_3 @@ -4802,9 +4707,9 @@ ir.cpp: # 830| r830_6(glval) = Convert : r830_5 # 830| r830_7(Derived &) = CopyValue : r830_6 # 830| r830_8(Derived &) = Call : func:r830_2, this:r830_1, 0:r830_7 -# 830| mu830_9(unknown) = ^CallSideEffect : ~mu799_4 -# 830| v830_10(void) = ^BufferReadSideEffect[-1] : &:r830_1, ~mu799_4 -# 830| v830_11(void) = ^BufferReadSideEffect[0] : &:r830_7, ~mu799_4 +# 830| mu830_9(unknown) = ^CallSideEffect : ~m? +# 830| v830_10(void) = ^BufferReadSideEffect[-1] : &:r830_1, ~m? +# 830| v830_11(void) = ^BufferReadSideEffect[0] : &:r830_7, ~m? # 830| mu830_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r830_1 # 830| mu830_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r830_7 # 830| r830_14(glval) = CopyValue : r830_8 @@ -4816,26 +4721,26 @@ ir.cpp: # 831| r831_6(glval) = Convert : r831_5 # 831| r831_7(Derived &) = CopyValue : r831_6 # 831| r831_8(Derived &) = Call : func:r831_2, this:r831_1, 0:r831_7 -# 831| mu831_9(unknown) = ^CallSideEffect : ~mu799_4 -# 831| v831_10(void) = ^BufferReadSideEffect[-1] : &:r831_1, ~mu799_4 -# 831| v831_11(void) = ^BufferReadSideEffect[0] : &:r831_7, ~mu799_4 +# 831| mu831_9(unknown) = ^CallSideEffect : ~m? +# 831| v831_10(void) = ^BufferReadSideEffect[-1] : &:r831_1, ~m? +# 831| v831_11(void) = ^BufferReadSideEffect[0] : &:r831_7, ~m? # 831| mu831_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r831_1 # 831| mu831_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r831_7 # 831| r831_14(glval) = CopyValue : r831_8 # 832| r832_1(glval) = VariableAddress[pb] : -# 832| r832_2(Base *) = Load : &:r832_1, ~mu799_4 +# 832| r832_2(Base *) = Load : &:r832_1, ~m? # 832| r832_3(Middle *) = ConvertToDerived[Middle : Base] : r832_2 # 832| r832_4(Derived *) = ConvertToDerived[Derived : Middle] : r832_3 # 832| r832_5(glval) = VariableAddress[pd] : # 832| mu832_6(Derived *) = Store : &:r832_5, r832_4 # 833| r833_1(glval) = VariableAddress[pb] : -# 833| r833_2(Base *) = Load : &:r833_1, ~mu799_4 +# 833| r833_2(Base *) = Load : &:r833_1, ~m? # 833| r833_3(Middle *) = ConvertToDerived[Middle : Base] : r833_2 # 833| r833_4(Derived *) = ConvertToDerived[Derived : Middle] : r833_3 # 833| r833_5(glval) = VariableAddress[pd] : # 833| mu833_6(Derived *) = Store : &:r833_5, r833_4 # 834| r834_1(glval) = VariableAddress[pb] : -# 834| r834_2(Base *) = Load : &:r834_1, ~mu799_4 +# 834| r834_2(Base *) = Load : &:r834_1, ~m? # 834| r834_3(Derived *) = Convert : r834_2 # 834| r834_4(glval) = VariableAddress[pd] : # 834| mu834_5(Derived *) = Store : &:r834_4, r834_3 @@ -4846,86 +4751,90 @@ ir.cpp: # 837| r837_2(DerivedVB *) = Constant[0] : # 837| mu837_3(DerivedVB *) = Store : &:r837_1, r837_2 # 838| r838_1(glval) = VariableAddress[pmv] : -# 838| r838_2(MiddleVB1 *) = Load : &:r838_1, ~mu799_4 +# 838| r838_2(MiddleVB1 *) = Load : &:r838_1, ~m? # 838| r838_3(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r838_2 # 838| r838_4(glval) = VariableAddress[pb] : # 838| mu838_5(Base *) = Store : &:r838_4, r838_3 # 839| r839_1(glval) = VariableAddress[pdv] : -# 839| r839_2(DerivedVB *) = Load : &:r839_1, ~mu799_4 +# 839| r839_2(DerivedVB *) = Load : &:r839_1, ~m? # 839| r839_3(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r839_2 # 839| r839_4(glval) = VariableAddress[pb] : # 839| mu839_5(Base *) = Store : &:r839_4, r839_3 # 840| v840_1(void) = NoOp : -# 799| v799_5(void) = ReturnVoid : -# 799| v799_6(void) = UnmodeledUse : mu* -# 799| v799_7(void) = AliasedUse : ~mu799_4 -# 799| v799_8(void) = ExitFunction : +# 799| v799_4(void) = ReturnVoid : +# 799| v799_5(void) = AliasedUse : ~m? +# 799| v799_6(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 -# 842| v842_1(void) = EnterFunction : -# 842| mu842_2(unknown) = AliasedDefinition : -# 842| mu842_3(unknown) = InitializeNonLocal : -# 842| mu842_4(unknown) = UnmodeledDefinition : -# 842| r842_5(glval) = InitializeThis : -# 842| v842_6(void) = NoOp : -# 842| v842_7(void) = ReturnVoid : -# 842| v842_8(void) = UnmodeledUse : mu* -# 842| v842_9(void) = AliasedUse : ~mu842_4 -# 842| v842_10(void) = ExitFunction : +# 842| v842_1(void) = EnterFunction : +# 842| mu842_2(unknown) = AliasedDefinition : +# 842| mu842_3(unknown) = InitializeNonLocal : +# 842| r842_4(glval) = VariableAddress[#this] : +# 842| mu842_5(glval) = InitializeParameter[#this] : &:r842_4 +# 842| r842_6(glval) = Load : &:r842_4, ~m? +# 842| mu842_7(PolymorphicBase) = InitializeIndirection[#this] : &:r842_6 +# 842| v842_8(void) = NoOp : +# 842| v842_9(void) = ReturnIndirection[#this] : &:r842_6, ~m? +# 842| v842_10(void) = ReturnVoid : +# 842| v842_11(void) = AliasedUse : ~m? +# 842| v842_12(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 -# 846| v846_1(void) = EnterFunction : -# 846| mu846_2(unknown) = AliasedDefinition : -# 846| mu846_3(unknown) = InitializeNonLocal : -# 846| mu846_4(unknown) = UnmodeledDefinition : -# 846| r846_5(glval) = InitializeThis : -# 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 -# 846| r846_7(glval) = FunctionAddress[PolymorphicBase] : -# 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~mu846_4 -# 846| mu846_10(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_6 -# 846| v846_11(void) = NoOp : -# 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = UnmodeledUse : mu* -# 846| v846_14(void) = AliasedUse : ~mu846_4 -# 846| v846_15(void) = ExitFunction : +# 846| v846_1(void) = EnterFunction : +# 846| mu846_2(unknown) = AliasedDefinition : +# 846| mu846_3(unknown) = InitializeNonLocal : +# 846| r846_4(glval) = VariableAddress[#this] : +# 846| mu846_5(glval) = InitializeParameter[#this] : &:r846_4 +# 846| r846_6(glval) = Load : &:r846_4, ~m? +# 846| mu846_7(PolymorphicDerived) = InitializeIndirection[#this] : &:r846_6 +# 846| r846_8(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : mu846_5 +# 846| r846_9(glval) = FunctionAddress[PolymorphicBase] : +# 846| v846_10(void) = Call : func:r846_9, this:r846_8 +# 846| mu846_11(unknown) = ^CallSideEffect : ~m? +# 846| mu846_12(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_8 +# 846| v846_13(void) = NoOp : +# 846| v846_14(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_15(void) = ReturnVoid : +# 846| v846_16(void) = AliasedUse : ~m? +# 846| v846_17(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 -# 846| v846_1(void) = EnterFunction : -# 846| mu846_2(unknown) = AliasedDefinition : -# 846| mu846_3(unknown) = InitializeNonLocal : -# 846| mu846_4(unknown) = UnmodeledDefinition : -# 846| r846_5(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 -# 846| r846_7(glval) = FunctionAddress[~PolymorphicBase] : -# 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~mu846_4 -# 846| v846_10(void) = ReturnVoid : -# 846| v846_11(void) = UnmodeledUse : mu* -# 846| v846_12(void) = AliasedUse : ~mu846_4 -# 846| v846_13(void) = ExitFunction : +# 846| v846_1(void) = EnterFunction : +# 846| mu846_2(unknown) = AliasedDefinition : +# 846| mu846_3(unknown) = InitializeNonLocal : +# 846| r846_4(glval) = VariableAddress[#this] : +# 846| mu846_5(glval) = InitializeParameter[#this] : &:r846_4 +# 846| r846_6(glval) = Load : &:r846_4, ~m? +# 846| mu846_7(PolymorphicDerived) = InitializeIndirection[#this] : &:r846_6 +#-----| v0_1(void) = NoOp : +# 846| r846_8(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : mu846_5 +# 846| r846_9(glval) = FunctionAddress[~PolymorphicBase] : +# 846| v846_10(void) = Call : func:r846_9, this:r846_8 +# 846| mu846_11(unknown) = ^CallSideEffect : ~m? +# 846| v846_12(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_13(void) = ReturnVoid : +# 846| v846_14(void) = AliasedUse : ~m? +# 846| v846_15(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 # 849| v849_1(void) = EnterFunction : # 849| mu849_2(unknown) = AliasedDefinition : # 849| mu849_3(unknown) = InitializeNonLocal : -# 849| mu849_4(unknown) = UnmodeledDefinition : # 850| r850_1(glval) = VariableAddress[b] : # 850| mu850_2(PolymorphicBase) = Uninitialized[b] : &:r850_1 #-----| r0_1(glval) = FunctionAddress[PolymorphicBase] : #-----| v0_2(void) = Call : func:r0_1, this:r850_1 -#-----| mu0_3(unknown) = ^CallSideEffect : ~mu849_4 +#-----| mu0_3(unknown) = ^CallSideEffect : ~m? #-----| mu0_4(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r850_1 # 851| r851_1(glval) = VariableAddress[d] : # 851| mu851_2(PolymorphicDerived) = Uninitialized[d] : &:r851_1 #-----| r0_5(glval) = FunctionAddress[PolymorphicDerived] : #-----| v0_6(void) = Call : func:r0_5, this:r851_1 -#-----| mu0_7(unknown) = ^CallSideEffect : ~mu849_4 +#-----| mu0_7(unknown) = ^CallSideEffect : ~m? #-----| mu0_8(PolymorphicDerived) = ^IndirectMayWriteSideEffect[-1] : &:r851_1 # 853| r853_1(glval) = VariableAddress[pb] : # 853| r853_2(glval) = VariableAddress[b] : @@ -4936,7 +4845,7 @@ ir.cpp: # 854| r854_3(PolymorphicDerived *) = CopyValue : r854_2 # 854| mu854_4(PolymorphicDerived *) = Store : &:r854_1, r854_3 # 857| r857_1(glval) = VariableAddress[pd] : -# 857| r857_2(PolymorphicDerived *) = Load : &:r857_1, ~mu849_4 +# 857| r857_2(PolymorphicDerived *) = Load : &:r857_1, ~m? # 857| r857_3(PolymorphicBase *) = CheckedConvertOrNull : r857_2 # 857| r857_4(glval) = VariableAddress[pb] : # 857| mu857_5(PolymorphicBase *) = Store : &:r857_4, r857_3 @@ -4946,7 +4855,7 @@ ir.cpp: # 858| r858_4(PolymorphicBase &) = CopyValue : r858_3 # 858| mu858_5(PolymorphicBase &) = Store : &:r858_1, r858_4 # 860| r860_1(glval) = VariableAddress[pb] : -# 860| r860_2(PolymorphicBase *) = Load : &:r860_1, ~mu849_4 +# 860| r860_2(PolymorphicBase *) = Load : &:r860_1, ~m? # 860| r860_3(PolymorphicDerived *) = CheckedConvertOrNull : r860_2 # 860| r860_4(glval) = VariableAddress[pd] : # 860| mu860_5(PolymorphicDerived *) = Store : &:r860_4, r860_3 @@ -4957,47 +4866,47 @@ ir.cpp: # 861| mu861_5(PolymorphicDerived &) = Store : &:r861_1, r861_4 # 863| r863_1(glval) = VariableAddress[pv] : # 863| r863_2(glval) = VariableAddress[pb] : -# 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~mu849_4 -# 863| r863_4(void *) = DynamicCastToVoid : r863_3 +# 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~m? +# 863| r863_4(void *) = CompleteObjectAddress : r863_3 # 863| mu863_5(void *) = Store : &:r863_1, r863_4 # 864| r864_1(glval) = VariableAddress[pcv] : # 864| r864_2(glval) = VariableAddress[pd] : -# 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~mu849_4 -# 864| r864_4(void *) = DynamicCastToVoid : r864_3 +# 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~m? +# 864| r864_4(void *) = CompleteObjectAddress : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : -# 849| v849_5(void) = ReturnVoid : -# 849| v849_6(void) = UnmodeledUse : mu* -# 849| v849_7(void) = AliasedUse : ~mu849_4 -# 849| v849_8(void) = ExitFunction : +# 849| v849_4(void) = ReturnVoid : +# 849| v849_5(void) = AliasedUse : ~m? +# 849| v849_6(void) = ExitFunction : # 867| void String::String() # 867| Block 0 # 867| v867_1(void) = EnterFunction : # 867| mu867_2(unknown) = AliasedDefinition : # 867| mu867_3(unknown) = InitializeNonLocal : -# 867| mu867_4(unknown) = UnmodeledDefinition : -# 867| r867_5(glval) = InitializeThis : +# 867| r867_4(glval) = VariableAddress[#this] : +# 867| mu867_5(glval) = InitializeParameter[#this] : &:r867_4 +# 867| r867_6(glval) = Load : &:r867_4, ~m? +# 867| mu867_7(String) = InitializeIndirection[#this] : &:r867_6 # 868| r868_1(glval) = FunctionAddress[String] : # 868| r868_2(glval) = StringConstant[""] : # 868| r868_3(char *) = Convert : r868_2 -# 868| v868_4(void) = Call : func:r868_1, this:r867_5, 0:r868_3 -# 868| mu868_5(unknown) = ^CallSideEffect : ~mu867_4 -# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r867_5 -# 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~mu867_4 +# 868| v868_4(void) = Call : func:r868_1, this:mu867_5, 0:r868_3 +# 868| mu868_5(unknown) = ^CallSideEffect : ~m? +# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:mu867_5 +# 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : -# 867| v867_6(void) = ReturnVoid : -# 867| v867_7(void) = UnmodeledUse : mu* -# 867| v867_8(void) = AliasedUse : ~mu867_4 -# 867| v867_9(void) = ExitFunction : +# 867| v867_8(void) = ReturnIndirection[#this] : &:r867_6, ~m? +# 867| v867_9(void) = ReturnVoid : +# 867| v867_10(void) = AliasedUse : ~m? +# 867| v867_11(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 # 871| v871_1(void) = EnterFunction : # 871| mu871_2(unknown) = AliasedDefinition : # 871| mu871_3(unknown) = InitializeNonLocal : -# 871| mu871_4(unknown) = UnmodeledDefinition : # 872| r872_1(glval) = VariableAddress[a] : # 872| mu872_2(char[5]) = Uninitialized[a] : &:r872_1 # 873| r873_1(glval) = VariableAddress[p] : @@ -5042,101 +4951,95 @@ ir.cpp: # 880| r880_3(glval) = VariableAddress[pa] : # 880| mu880_4(char(*)[5]) = Store : &:r880_3, r880_2 # 881| v881_1(void) = NoOp : -# 871| v871_5(void) = ReturnVoid : -# 871| v871_6(void) = UnmodeledUse : mu* -# 871| v871_7(void) = AliasedUse : ~mu871_4 -# 871| v871_8(void) = ExitFunction : +# 871| v871_4(void) = ReturnVoid : +# 871| v871_5(void) = AliasedUse : ~m? +# 871| v871_6(void) = ExitFunction : # 883| void FuncPtrConversions(int(*)(int), void*) # 883| Block 0 # 883| v883_1(void) = EnterFunction : # 883| mu883_2(unknown) = AliasedDefinition : # 883| mu883_3(unknown) = InitializeNonLocal : -# 883| mu883_4(unknown) = UnmodeledDefinition : -# 883| r883_5(glval<..(*)(..)>) = VariableAddress[pfn] : -# 883| mu883_6(..(*)(..)) = InitializeParameter[pfn] : &:r883_5 -# 883| r883_7(glval) = VariableAddress[p] : -# 883| mu883_8(void *) = InitializeParameter[p] : &:r883_7 -# 883| r883_9(void *) = Load : &:r883_7, ~mu883_4 -# 883| mu883_10(unknown) = InitializeIndirection[p] : &:r883_9 +# 883| r883_4(glval<..(*)(..)>) = VariableAddress[pfn] : +# 883| mu883_5(..(*)(..)) = InitializeParameter[pfn] : &:r883_4 +# 883| r883_6(glval) = VariableAddress[p] : +# 883| mu883_7(void *) = InitializeParameter[p] : &:r883_6 +# 883| r883_8(void *) = Load : &:r883_6, ~m? +# 883| mu883_9(unknown) = InitializeIndirection[p] : &:r883_8 # 884| r884_1(glval<..(*)(..)>) = VariableAddress[pfn] : -# 884| r884_2(..(*)(..)) = Load : &:r884_1, ~mu883_4 +# 884| r884_2(..(*)(..)) = Load : &:r884_1, ~m? # 884| r884_3(void *) = Convert : r884_2 # 884| r884_4(glval) = VariableAddress[p] : # 884| mu884_5(void *) = Store : &:r884_4, r884_3 # 885| r885_1(glval) = VariableAddress[p] : -# 885| r885_2(void *) = Load : &:r885_1, ~mu883_4 +# 885| r885_2(void *) = Load : &:r885_1, ~m? # 885| r885_3(..(*)(..)) = Convert : r885_2 # 885| r885_4(glval<..(*)(..)>) = VariableAddress[pfn] : # 885| mu885_5(..(*)(..)) = Store : &:r885_4, r885_3 # 886| v886_1(void) = NoOp : -# 883| v883_11(void) = ReturnIndirection[p] : &:r883_9, ~mu883_4 -# 883| v883_12(void) = ReturnVoid : -# 883| v883_13(void) = UnmodeledUse : mu* -# 883| v883_14(void) = AliasedUse : ~mu883_4 -# 883| v883_15(void) = ExitFunction : +# 883| v883_10(void) = ReturnIndirection[p] : &:r883_8, ~m? +# 883| v883_11(void) = ReturnVoid : +# 883| v883_12(void) = AliasedUse : ~m? +# 883| v883_13(void) = ExitFunction : # 888| void VAListUsage(int, __va_list_tag[1]) # 888| Block 0 # 888| v888_1(void) = EnterFunction : # 888| mu888_2(unknown) = AliasedDefinition : # 888| mu888_3(unknown) = InitializeNonLocal : -# 888| mu888_4(unknown) = UnmodeledDefinition : -# 888| r888_5(glval) = VariableAddress[x] : -# 888| mu888_6(int) = InitializeParameter[x] : &:r888_5 -# 888| r888_7(glval<__va_list_tag *>) = VariableAddress[args] : -# 888| mu888_8(__va_list_tag *) = InitializeParameter[args] : &:r888_7 -# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~mu888_4 -# 888| mu888_10(unknown) = InitializeIndirection[args] : &:r888_9 +# 888| r888_4(glval) = VariableAddress[x] : +# 888| mu888_5(int) = InitializeParameter[x] : &:r888_4 +# 888| r888_6(glval<__va_list_tag *>) = VariableAddress[args] : +# 888| mu888_7(__va_list_tag *) = InitializeParameter[args] : &:r888_6 +# 888| r888_8(__va_list_tag *) = Load : &:r888_6, ~m? +# 888| mu888_9(unknown) = InitializeIndirection[args] : &:r888_8 # 889| r889_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 889| mu889_2(__va_list_tag[1]) = Uninitialized[args2] : &:r889_1 # 890| r890_1(glval<__va_list_tag *>) = VariableAddress[args] : -# 890| r890_2(__va_list_tag *) = Load : &:r890_1, ~mu888_4 -# 890| r890_3(__va_list_tag) = Load : &:r890_2, ~mu888_4 +# 890| r890_2(__va_list_tag *) = Load : &:r890_1, ~m? +# 890| r890_3(__va_list_tag) = Load : &:r890_2, ~m? # 890| r890_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 890| r890_5(__va_list_tag *) = Convert : r890_4 # 890| mu890_6(__va_list_tag) = Store : &:r890_5, r890_3 # 891| r891_1(glval) = VariableAddress[d] : # 891| r891_2(glval<__va_list_tag *>) = VariableAddress[args] : -# 891| r891_3(__va_list_tag *) = Load : &:r891_2, ~mu888_4 -# 891| r891_4(__va_list_tag) = Load : &:r891_3, ~mu888_4 +# 891| r891_3(__va_list_tag *) = Load : &:r891_2, ~m? +# 891| r891_4(__va_list_tag) = Load : &:r891_3, ~m? # 891| r891_5(glval) = VarArg : r891_4 # 891| r891_6(__va_list_tag) = NextVarArg : r891_4 # 891| mu891_7(__va_list_tag) = Store : &:r891_3, r891_6 -# 891| r891_8(double) = Load : &:r891_5, ~mu888_4 +# 891| r891_8(double) = Load : &:r891_5, ~m? # 891| mu891_9(double) = Store : &:r891_1, r891_8 # 892| r892_1(glval) = VariableAddress[f] : # 892| r892_2(glval<__va_list_tag *>) = VariableAddress[args] : -# 892| r892_3(__va_list_tag *) = Load : &:r892_2, ~mu888_4 -# 892| r892_4(__va_list_tag) = Load : &:r892_3, ~mu888_4 +# 892| r892_3(__va_list_tag *) = Load : &:r892_2, ~m? +# 892| r892_4(__va_list_tag) = Load : &:r892_3, ~m? # 892| r892_5(glval) = VarArg : r892_4 # 892| r892_6(__va_list_tag) = NextVarArg : r892_4 # 892| mu892_7(__va_list_tag) = Store : &:r892_3, r892_6 -# 892| r892_8(int) = Load : &:r892_5, ~mu888_4 +# 892| r892_8(int) = Load : &:r892_5, ~m? # 892| r892_9(float) = Convert : r892_8 # 892| mu892_10(float) = Store : &:r892_1, r892_9 # 893| r893_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 893| r893_2(__va_list_tag *) = Convert : r893_1 # 893| v893_3(void) = VarArgsEnd : r893_2 # 894| v894_1(void) = NoOp : -# 888| v888_11(void) = ReturnIndirection[args] : &:r888_9, ~mu888_4 -# 888| v888_12(void) = ReturnVoid : -# 888| v888_13(void) = UnmodeledUse : mu* -# 888| v888_14(void) = AliasedUse : ~mu888_4 -# 888| v888_15(void) = ExitFunction : +# 888| v888_10(void) = ReturnIndirection[args] : &:r888_8, ~m? +# 888| v888_11(void) = ReturnVoid : +# 888| v888_12(void) = AliasedUse : ~m? +# 888| v888_13(void) = ExitFunction : # 896| void VarArgUsage(int) # 896| Block 0 # 896| v896_1(void) = EnterFunction : # 896| mu896_2(unknown) = AliasedDefinition : # 896| mu896_3(unknown) = InitializeNonLocal : -# 896| mu896_4(unknown) = UnmodeledDefinition : -# 896| r896_5(glval) = VariableAddress[x] : -# 896| mu896_6(int) = InitializeParameter[x] : &:r896_5 -# 896| r896_7(glval) = VariableAddress[#ellipsis] : -# 896| mu896_8(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_7 -# 896| r896_9(unknown[11]) = Load : &:r896_7, ~mu896_4 -# 896| mu896_10(unknown) = InitializeIndirection[#ellipsis] : &:r896_9 +# 896| r896_4(glval) = VariableAddress[x] : +# 896| mu896_5(int) = InitializeParameter[x] : &:r896_4 +# 896| r896_6(glval) = VariableAddress[#ellipsis] : +# 896| mu896_7(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_6 +# 896| r896_8(unknown[11]) = Load : &:r896_6, ~m? +# 896| mu896_9(unknown) = InitializeIndirection[#ellipsis] : &:r896_8 # 897| r897_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 897| mu897_2(__va_list_tag[1]) = Uninitialized[args] : &:r897_1 # 899| r899_1(glval) = VariableAddress[#ellipsis] : @@ -5148,27 +5051,27 @@ ir.cpp: # 900| mu900_2(__va_list_tag[1]) = Uninitialized[args2] : &:r900_1 # 901| r901_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 901| r901_2(__va_list_tag *) = Convert : r901_1 -# 901| r901_3(__va_list_tag) = Load : &:r901_2, ~mu896_4 +# 901| r901_3(__va_list_tag) = Load : &:r901_2, ~m? # 901| r901_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 901| r901_5(__va_list_tag *) = Convert : r901_4 # 901| mu901_6(__va_list_tag) = Store : &:r901_5, r901_3 # 902| r902_1(glval) = VariableAddress[d] : # 902| r902_2(glval<__va_list_tag[1]>) = VariableAddress[args] : # 902| r902_3(__va_list_tag *) = Convert : r902_2 -# 902| r902_4(__va_list_tag) = Load : &:r902_3, ~mu896_4 +# 902| r902_4(__va_list_tag) = Load : &:r902_3, ~m? # 902| r902_5(glval) = VarArg : r902_4 # 902| r902_6(__va_list_tag) = NextVarArg : r902_4 # 902| mu902_7(__va_list_tag) = Store : &:r902_3, r902_6 -# 902| r902_8(double) = Load : &:r902_5, ~mu896_4 +# 902| r902_8(double) = Load : &:r902_5, ~m? # 902| mu902_9(double) = Store : &:r902_1, r902_8 # 903| r903_1(glval) = VariableAddress[f] : # 903| r903_2(glval<__va_list_tag[1]>) = VariableAddress[args] : # 903| r903_3(__va_list_tag *) = Convert : r903_2 -# 903| r903_4(__va_list_tag) = Load : &:r903_3, ~mu896_4 +# 903| r903_4(__va_list_tag) = Load : &:r903_3, ~m? # 903| r903_5(glval) = VarArg : r903_4 # 903| r903_6(__va_list_tag) = NextVarArg : r903_4 # 903| mu903_7(__va_list_tag) = Store : &:r903_3, r903_6 -# 903| r903_8(int) = Load : &:r903_5, ~mu896_4 +# 903| r903_8(int) = Load : &:r903_5, ~m? # 903| r903_9(float) = Convert : r903_8 # 903| mu903_10(float) = Store : &:r903_1, r903_9 # 904| r904_1(glval<__va_list_tag[1]>) = VariableAddress[args] : @@ -5176,46 +5079,42 @@ ir.cpp: # 904| v904_3(void) = VarArgsEnd : r904_2 # 905| r905_1(glval) = FunctionAddress[VAListUsage] : # 905| r905_2(glval) = VariableAddress[x] : -# 905| r905_3(int) = Load : &:r905_2, ~mu896_4 +# 905| r905_3(int) = Load : &:r905_2, ~m? # 905| r905_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 905| r905_5(__va_list_tag *) = Convert : r905_4 # 905| v905_6(void) = Call : func:r905_1, 0:r905_3, 1:r905_5 -# 905| mu905_7(unknown) = ^CallSideEffect : ~mu896_4 -# 905| v905_8(void) = ^BufferReadSideEffect[1] : &:r905_5, ~mu896_4 +# 905| mu905_7(unknown) = ^CallSideEffect : ~m? +# 905| v905_8(void) = ^BufferReadSideEffect[1] : &:r905_5, ~m? # 905| mu905_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r905_5 # 906| r906_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 906| r906_2(__va_list_tag *) = Convert : r906_1 # 906| v906_3(void) = VarArgsEnd : r906_2 # 907| v907_1(void) = NoOp : -# 896| v896_11(void) = ReturnVoid : -# 896| v896_12(void) = UnmodeledUse : mu* -# 896| v896_13(void) = AliasedUse : ~mu896_4 -# 896| v896_14(void) = ExitFunction : +# 896| v896_10(void) = ReturnVoid : +# 896| v896_11(void) = AliasedUse : ~m? +# 896| v896_12(void) = ExitFunction : # 909| void CastToVoid(int) # 909| Block 0 # 909| v909_1(void) = EnterFunction : # 909| mu909_2(unknown) = AliasedDefinition : # 909| mu909_3(unknown) = InitializeNonLocal : -# 909| mu909_4(unknown) = UnmodeledDefinition : -# 909| r909_5(glval) = VariableAddress[x] : -# 909| mu909_6(int) = InitializeParameter[x] : &:r909_5 +# 909| r909_4(glval) = VariableAddress[x] : +# 909| mu909_5(int) = InitializeParameter[x] : &:r909_4 # 910| r910_1(glval) = VariableAddress[x] : # 910| v910_2(void) = Convert : r910_1 # 911| v911_1(void) = NoOp : -# 909| v909_7(void) = ReturnVoid : -# 909| v909_8(void) = UnmodeledUse : mu* -# 909| v909_9(void) = AliasedUse : ~mu909_4 -# 909| v909_10(void) = ExitFunction : +# 909| v909_6(void) = ReturnVoid : +# 909| v909_7(void) = AliasedUse : ~m? +# 909| v909_8(void) = ExitFunction : # 913| void ConstantConditions(int) # 913| Block 0 # 913| v913_1(void) = EnterFunction : # 913| mu913_2(unknown) = AliasedDefinition : # 913| mu913_3(unknown) = InitializeNonLocal : -# 913| mu913_4(unknown) = UnmodeledDefinition : -# 913| r913_5(glval) = VariableAddress[x] : -# 913| mu913_6(int) = InitializeParameter[x] : &:r913_5 +# 913| r913_4(glval) = VariableAddress[x] : +# 913| mu913_5(int) = InitializeParameter[x] : &:r913_4 # 914| r914_1(glval) = VariableAddress[a] : # 914| r914_2(bool) = Constant[1] : # 914| mu914_3(bool) = Store : &:r914_1, r914_2 @@ -5227,24 +5126,23 @@ ir.cpp: # 915| Block 1 # 915| r915_4(glval) = VariableAddress[#temp915:11] : -# 915| r915_5(int) = Load : &:r915_4, ~mu913_4 +# 915| r915_5(int) = Load : &:r915_4, ~m? # 915| mu915_6(int) = Store : &:r915_1, r915_5 # 916| v916_1(void) = NoOp : -# 913| v913_7(void) = ReturnVoid : -# 913| v913_8(void) = UnmodeledUse : mu* -# 913| v913_9(void) = AliasedUse : ~mu913_4 -# 913| v913_10(void) = ExitFunction : +# 913| v913_6(void) = ReturnVoid : +# 913| v913_7(void) = AliasedUse : ~m? +# 913| v913_8(void) = ExitFunction : # 915| Block 2 # 915| r915_7(glval) = VariableAddress[x] : -# 915| r915_8(int) = Load : &:r915_7, ~mu913_4 +# 915| r915_8(int) = Load : &:r915_7, ~m? # 915| r915_9(glval) = VariableAddress[#temp915:11] : # 915| mu915_10(int) = Store : &:r915_9, r915_8 #-----| Goto -> Block 1 # 915| Block 3 # 915| r915_11(glval) = VariableAddress[x] : -# 915| r915_12(int) = Load : &:r915_11, ~mu913_4 +# 915| r915_12(int) = Load : &:r915_11, ~m? # 915| r915_13(glval) = VariableAddress[#temp915:11] : # 915| mu915_14(int) = Store : &:r915_13, r915_12 #-----| Goto -> Block 1 @@ -5254,24 +5152,23 @@ ir.cpp: # 949| v949_1(void) = EnterFunction : # 949| mu949_2(unknown) = AliasedDefinition : # 949| mu949_3(unknown) = InitializeNonLocal : -# 949| mu949_4(unknown) = UnmodeledDefinition : # 950| r950_1(glval) = FunctionAddress[operator new] : # 950| r950_2(unsigned long) = Constant[4] : # 950| r950_3(void *) = Call : func:r950_1, 0:r950_2 -# 950| mu950_4(unknown) = ^CallSideEffect : ~mu949_4 +# 950| mu950_4(unknown) = ^CallSideEffect : ~m? # 950| mu950_5(unknown) = ^InitializeDynamicAllocation : &:r950_3 # 950| r950_6(int *) = Convert : r950_3 # 951| r951_1(glval) = FunctionAddress[operator new] : # 951| r951_2(unsigned long) = Constant[4] : # 951| r951_3(float) = Constant[1.0] : # 951| r951_4(void *) = Call : func:r951_1, 0:r951_2, 1:r951_3 -# 951| mu951_5(unknown) = ^CallSideEffect : ~mu949_4 +# 951| mu951_5(unknown) = ^CallSideEffect : ~m? # 951| mu951_6(unknown) = ^InitializeDynamicAllocation : &:r951_4 # 951| r951_7(int *) = Convert : r951_4 # 952| r952_1(glval) = FunctionAddress[operator new] : # 952| r952_2(unsigned long) = Constant[4] : # 952| r952_3(void *) = Call : func:r952_1, 0:r952_2 -# 952| mu952_4(unknown) = ^CallSideEffect : ~mu949_4 +# 952| mu952_4(unknown) = ^CallSideEffect : ~m? # 952| mu952_5(unknown) = ^InitializeDynamicAllocation : &:r952_3 # 952| r952_6(int *) = Convert : r952_3 # 952| r952_7(int) = Constant[0] : @@ -5279,33 +5176,33 @@ ir.cpp: # 953| r953_1(glval) = FunctionAddress[operator new] : # 953| r953_2(unsigned long) = Constant[8] : # 953| r953_3(void *) = Call : func:r953_1, 0:r953_2 -# 953| mu953_4(unknown) = ^CallSideEffect : ~mu949_4 +# 953| mu953_4(unknown) = ^CallSideEffect : ~m? # 953| mu953_5(unknown) = ^InitializeDynamicAllocation : &:r953_3 # 953| r953_6(String *) = Convert : r953_3 # 953| r953_7(glval) = FunctionAddress[String] : # 953| v953_8(void) = Call : func:r953_7, this:r953_6 -# 953| mu953_9(unknown) = ^CallSideEffect : ~mu949_4 +# 953| mu953_9(unknown) = ^CallSideEffect : ~m? # 953| mu953_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r953_6 # 954| r954_1(glval) = FunctionAddress[operator new] : # 954| r954_2(unsigned long) = Constant[8] : # 954| r954_3(float) = Constant[1.0] : # 954| r954_4(void *) = Call : func:r954_1, 0:r954_2, 1:r954_3 -# 954| mu954_5(unknown) = ^CallSideEffect : ~mu949_4 +# 954| mu954_5(unknown) = ^CallSideEffect : ~m? # 954| mu954_6(unknown) = ^InitializeDynamicAllocation : &:r954_4 # 954| r954_7(String *) = Convert : r954_4 # 954| r954_8(glval) = FunctionAddress[String] : # 954| r954_9(glval) = StringConstant["hello"] : # 954| r954_10(char *) = Convert : r954_9 # 954| v954_11(void) = Call : func:r954_8, this:r954_7, 0:r954_10 -# 954| mu954_12(unknown) = ^CallSideEffect : ~mu949_4 +# 954| mu954_12(unknown) = ^CallSideEffect : ~m? # 954| mu954_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r954_7 -# 954| v954_14(void) = ^BufferReadSideEffect[0] : &:r954_10, ~mu949_4 +# 954| v954_14(void) = ^BufferReadSideEffect[0] : &:r954_10, ~m? # 954| mu954_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r954_10 # 955| r955_1(glval) = FunctionAddress[operator new] : # 955| r955_2(unsigned long) = Constant[256] : # 955| r955_3(align_val_t) = Constant[128] : # 955| r955_4(void *) = Call : func:r955_1, 0:r955_2, 1:r955_3 -# 955| mu955_5(unknown) = ^CallSideEffect : ~mu949_4 +# 955| mu955_5(unknown) = ^CallSideEffect : ~m? # 955| mu955_6(unknown) = ^InitializeDynamicAllocation : &:r955_4 # 955| r955_7(Overaligned *) = Convert : r955_4 # 956| r956_1(glval) = FunctionAddress[operator new] : @@ -5313,71 +5210,69 @@ ir.cpp: # 956| r956_3(align_val_t) = Constant[128] : # 956| r956_4(float) = Constant[1.0] : # 956| r956_5(void *) = Call : func:r956_1, 0:r956_2, 1:r956_3, 2:r956_4 -# 956| mu956_6(unknown) = ^CallSideEffect : ~mu949_4 +# 956| mu956_6(unknown) = ^CallSideEffect : ~m? # 956| mu956_7(unknown) = ^InitializeDynamicAllocation : &:r956_5 # 956| r956_8(Overaligned *) = Convert : r956_5 # 956| r956_9(Overaligned) = Constant[0] : # 956| mu956_10(Overaligned) = Store : &:r956_8, r956_9 # 957| v957_1(void) = NoOp : -# 949| v949_5(void) = ReturnVoid : -# 949| v949_6(void) = UnmodeledUse : mu* -# 949| v949_7(void) = AliasedUse : ~mu949_4 -# 949| v949_8(void) = ExitFunction : +# 949| v949_4(void) = ReturnVoid : +# 949| v949_5(void) = AliasedUse : ~m? +# 949| v949_6(void) = ExitFunction : # 959| void OperatorNewArray(int) # 959| Block 0 # 959| v959_1(void) = EnterFunction : # 959| mu959_2(unknown) = AliasedDefinition : # 959| mu959_3(unknown) = InitializeNonLocal : -# 959| mu959_4(unknown) = UnmodeledDefinition : -# 959| r959_5(glval) = VariableAddress[n] : -# 959| mu959_6(int) = InitializeParameter[n] : &:r959_5 +# 959| r959_4(glval) = VariableAddress[n] : +# 959| mu959_5(int) = InitializeParameter[n] : &:r959_4 # 960| r960_1(glval) = FunctionAddress[operator new[]] : # 960| r960_2(unsigned long) = Constant[40] : # 960| r960_3(void *) = Call : func:r960_1, 0:r960_2 -# 960| mu960_4(unknown) = ^CallSideEffect : ~mu959_4 +# 960| mu960_4(unknown) = ^CallSideEffect : ~m? # 960| mu960_5(unknown) = ^InitializeDynamicAllocation : &:r960_3 # 960| r960_6(int *) = Convert : r960_3 # 961| r961_1(glval) = FunctionAddress[operator new[]] : # 961| r961_2(glval) = VariableAddress[n] : -# 961| r961_3(int) = Load : &:r961_2, ~mu959_4 +# 961| r961_3(int) = Load : &:r961_2, ~m? # 961| r961_4(unsigned long) = Convert : r961_3 # 961| r961_5(unsigned long) = Constant[4] : # 961| r961_6(unsigned long) = Mul : r961_4, r961_5 # 961| r961_7(void *) = Call : func:r961_1, 0:r961_6 -# 961| mu961_8(unknown) = ^CallSideEffect : ~mu959_4 +# 961| mu961_8(unknown) = ^CallSideEffect : ~m? # 961| mu961_9(unknown) = ^InitializeDynamicAllocation : &:r961_7 # 961| r961_10(int *) = Convert : r961_7 # 962| r962_1(glval) = FunctionAddress[operator new[]] : # 962| r962_2(glval) = VariableAddress[n] : -# 962| r962_3(int) = Load : &:r962_2, ~mu959_4 +# 962| r962_3(int) = Load : &:r962_2, ~m? # 962| r962_4(unsigned long) = Convert : r962_3 # 962| r962_5(unsigned long) = Constant[4] : # 962| r962_6(unsigned long) = Mul : r962_4, r962_5 # 962| r962_7(float) = Constant[1.0] : # 962| r962_8(void *) = Call : func:r962_1, 0:r962_6, 1:r962_7 -# 962| mu962_9(unknown) = ^CallSideEffect : ~mu959_4 +# 962| mu962_9(unknown) = ^CallSideEffect : ~m? # 962| mu962_10(unknown) = ^InitializeDynamicAllocation : &:r962_8 # 962| r962_11(int *) = Convert : r962_8 # 963| r963_1(glval) = FunctionAddress[operator new[]] : # 963| r963_2(glval) = VariableAddress[n] : -# 963| r963_3(int) = Load : &:r963_2, ~mu959_4 +# 963| r963_3(int) = Load : &:r963_2, ~m? # 963| r963_4(unsigned long) = Convert : r963_3 # 963| r963_5(unsigned long) = Constant[8] : # 963| r963_6(unsigned long) = Mul : r963_4, r963_5 # 963| r963_7(void *) = Call : func:r963_1, 0:r963_6 -# 963| mu963_8(unknown) = ^CallSideEffect : ~mu959_4 +# 963| mu963_8(unknown) = ^CallSideEffect : ~m? # 963| mu963_9(unknown) = ^InitializeDynamicAllocation : &:r963_7 # 963| r963_10(String *) = Convert : r963_7 # 964| r964_1(glval) = FunctionAddress[operator new[]] : # 964| r964_2(glval) = VariableAddress[n] : -# 964| r964_3(int) = Load : &:r964_2, ~mu959_4 +# 964| r964_3(int) = Load : &:r964_2, ~m? # 964| r964_4(unsigned long) = Convert : r964_3 # 964| r964_5(unsigned long) = Constant[256] : # 964| r964_6(unsigned long) = Mul : r964_4, r964_5 # 964| r964_7(align_val_t) = Constant[128] : # 964| r964_8(void *) = Call : func:r964_1, 0:r964_6, 1:r964_7 -# 964| mu964_9(unknown) = ^CallSideEffect : ~mu959_4 +# 964| mu964_9(unknown) = ^CallSideEffect : ~m? # 964| mu964_10(unknown) = ^InitializeDynamicAllocation : &:r964_8 # 964| r964_11(Overaligned *) = Convert : r964_8 # 965| r965_1(glval) = FunctionAddress[operator new[]] : @@ -5385,41 +5280,39 @@ ir.cpp: # 965| r965_3(align_val_t) = Constant[128] : # 965| r965_4(float) = Constant[1.0] : # 965| r965_5(void *) = Call : func:r965_1, 0:r965_2, 1:r965_3, 2:r965_4 -# 965| mu965_6(unknown) = ^CallSideEffect : ~mu959_4 +# 965| mu965_6(unknown) = ^CallSideEffect : ~m? # 965| mu965_7(unknown) = ^InitializeDynamicAllocation : &:r965_5 # 965| r965_8(Overaligned *) = Convert : r965_5 # 966| r966_1(glval) = FunctionAddress[operator new[]] : # 966| r966_2(glval) = VariableAddress[n] : -# 966| r966_3(int) = Load : &:r966_2, ~mu959_4 +# 966| r966_3(int) = Load : &:r966_2, ~m? # 966| r966_4(unsigned long) = Convert : r966_3 # 966| r966_5(unsigned long) = Constant[1] : # 966| r966_6(unsigned long) = Mul : r966_4, r966_5 # 966| r966_7(void *) = Call : func:r966_1, 0:r966_6 -# 966| mu966_8(unknown) = ^CallSideEffect : ~mu959_4 +# 966| mu966_8(unknown) = ^CallSideEffect : ~m? # 966| mu966_9(unknown) = ^InitializeDynamicAllocation : &:r966_7 # 966| r966_10(DefaultCtorWithDefaultParam *) = Convert : r966_7 # 967| r967_1(glval) = FunctionAddress[operator new[]] : # 967| r967_2(glval) = VariableAddress[n] : -# 967| r967_3(int) = Load : &:r967_2, ~mu959_4 +# 967| r967_3(int) = Load : &:r967_2, ~m? # 967| r967_4(unsigned long) = Convert : r967_3 # 967| r967_5(unsigned long) = Constant[4] : # 967| r967_6(unsigned long) = Mul : r967_4, r967_5 # 967| r967_7(void *) = Call : func:r967_1, 0:r967_6 -# 967| mu967_8(unknown) = ^CallSideEffect : ~mu959_4 +# 967| mu967_8(unknown) = ^CallSideEffect : ~m? # 967| mu967_9(unknown) = ^InitializeDynamicAllocation : &:r967_7 # 967| r967_10(int *) = Convert : r967_7 # 968| v968_1(void) = NoOp : -# 959| v959_7(void) = ReturnVoid : -# 959| v959_8(void) = UnmodeledUse : mu* -# 959| v959_9(void) = AliasedUse : ~mu959_4 -# 959| v959_10(void) = ExitFunction : +# 959| v959_6(void) = ReturnVoid : +# 959| v959_7(void) = AliasedUse : ~m? +# 959| v959_8(void) = ExitFunction : # 970| int designatedInit() # 970| Block 0 # 970| v970_1(void) = EnterFunction : # 970| mu970_2(unknown) = AliasedDefinition : # 970| mu970_3(unknown) = InitializeNonLocal : -# 970| mu970_4(unknown) = UnmodeledDefinition : # 971| r971_1(glval) = VariableAddress[a1] : # 971| mu971_2(int[1000]) = Uninitialized[a1] : &:r971_1 # 971| r971_3(int) = Constant[0] : @@ -5447,33 +5340,31 @@ ir.cpp: # 972| r972_3(int *) = Convert : r972_2 # 972| r972_4(int) = Constant[900] : # 972| r972_5(glval) = PointerAdd[4] : r972_3, r972_4 -# 972| r972_6(int) = Load : &:r972_5, ~mu970_4 +# 972| r972_6(int) = Load : &:r972_5, ~m? # 972| mu972_7(int) = Store : &:r972_1, r972_6 -# 970| r970_5(glval) = VariableAddress[#return] : -# 970| v970_6(void) = ReturnValue : &:r970_5, ~mu970_4 -# 970| v970_7(void) = UnmodeledUse : mu* -# 970| v970_8(void) = AliasedUse : ~mu970_4 -# 970| v970_9(void) = ExitFunction : +# 970| r970_4(glval) = VariableAddress[#return] : +# 970| v970_5(void) = ReturnValue : &:r970_4, ~m? +# 970| v970_6(void) = AliasedUse : ~m? +# 970| v970_7(void) = ExitFunction : # 975| void IfStmtWithDeclaration(int, int) # 975| Block 0 # 975| v975_1(void) = EnterFunction : # 975| mu975_2(unknown) = AliasedDefinition : # 975| mu975_3(unknown) = InitializeNonLocal : -# 975| mu975_4(unknown) = UnmodeledDefinition : -# 975| r975_5(glval) = VariableAddress[x] : -# 975| mu975_6(int) = InitializeParameter[x] : &:r975_5 -# 975| r975_7(glval) = VariableAddress[y] : -# 975| mu975_8(int) = InitializeParameter[y] : &:r975_7 +# 975| r975_4(glval) = VariableAddress[x] : +# 975| mu975_5(int) = InitializeParameter[x] : &:r975_4 +# 975| r975_6(glval) = VariableAddress[y] : +# 975| mu975_7(int) = InitializeParameter[y] : &:r975_6 # 976| r976_1(glval) = VariableAddress[b] : # 976| r976_2(glval) = VariableAddress[x] : -# 976| r976_3(int) = Load : &:r976_2, ~mu975_4 +# 976| r976_3(int) = Load : &:r976_2, ~m? # 976| r976_4(glval) = VariableAddress[y] : -# 976| r976_5(int) = Load : &:r976_4, ~mu975_4 +# 976| r976_5(int) = Load : &:r976_4, ~m? # 976| r976_6(bool) = CompareLT : r976_3, r976_5 # 976| mu976_7(bool) = Store : &:r976_1, r976_6 # 976| r976_8(glval) = VariableAddress[b] : -# 976| r976_9(bool) = Load : &:r976_8, ~mu975_4 +# 976| r976_9(bool) = Load : &:r976_8, ~m? # 976| r976_10(bool) = CopyValue : r976_9 # 976| v976_11(void) = ConditionalBranch : r976_10 #-----| False -> Block 2 @@ -5488,13 +5379,13 @@ ir.cpp: # 979| Block 2 # 979| r979_1(glval) = VariableAddress[z] : # 979| r979_2(glval) = VariableAddress[x] : -# 979| r979_3(int) = Load : &:r979_2, ~mu975_4 +# 979| r979_3(int) = Load : &:r979_2, ~m? # 979| r979_4(glval) = VariableAddress[y] : -# 979| r979_5(int) = Load : &:r979_4, ~mu975_4 +# 979| r979_5(int) = Load : &:r979_4, ~m? # 979| r979_6(int) = Add : r979_3, r979_5 # 979| mu979_7(int) = Store : &:r979_1, r979_6 # 979| r979_8(glval) = VariableAddress[z] : -# 979| r979_9(int) = Load : &:r979_8, ~mu975_4 +# 979| r979_9(int) = Load : &:r979_8, ~m? # 979| r979_10(int) = Constant[0] : # 979| r979_11(bool) = CompareNE : r979_9, r979_10 # 979| r979_12(bool) = CopyValue : r979_11 @@ -5514,7 +5405,7 @@ ir.cpp: # 982| r982_3(int *) = CopyValue : r982_2 # 982| mu982_4(int *) = Store : &:r982_1, r982_3 # 982| r982_5(glval) = VariableAddress[p] : -# 982| r982_6(int *) = Load : &:r982_5, ~mu975_4 +# 982| r982_6(int *) = Load : &:r982_5, ~m? # 982| r982_7(int *) = Constant[0] : # 982| r982_8(bool) = CompareNE : r982_6, r982_7 # 982| r982_9(bool) = CopyValue : r982_8 @@ -5525,28 +5416,26 @@ ir.cpp: # 983| Block 5 # 983| r983_1(int) = Constant[2] : # 983| r983_2(glval) = VariableAddress[p] : -# 983| r983_3(int *) = Load : &:r983_2, ~mu975_4 +# 983| r983_3(int *) = Load : &:r983_2, ~m? # 983| r983_4(glval) = CopyValue : r983_3 # 983| mu983_5(int) = Store : &:r983_4, r983_1 #-----| Goto -> Block 6 # 985| Block 6 # 985| v985_1(void) = NoOp : -# 975| v975_9(void) = ReturnVoid : -# 975| v975_10(void) = UnmodeledUse : mu* -# 975| v975_11(void) = AliasedUse : ~mu975_4 -# 975| v975_12(void) = ExitFunction : +# 975| v975_8(void) = ReturnVoid : +# 975| v975_9(void) = AliasedUse : ~m? +# 975| v975_10(void) = ExitFunction : # 987| void WhileStmtWithDeclaration(int, int) # 987| Block 0 # 987| v987_1(void) = EnterFunction : # 987| mu987_2(unknown) = AliasedDefinition : # 987| mu987_3(unknown) = InitializeNonLocal : -# 987| mu987_4(unknown) = UnmodeledDefinition : -# 987| r987_5(glval) = VariableAddress[x] : -# 987| mu987_6(int) = InitializeParameter[x] : &:r987_5 -# 987| r987_7(glval) = VariableAddress[y] : -# 987| mu987_8(int) = InitializeParameter[y] : &:r987_7 +# 987| r987_4(glval) = VariableAddress[x] : +# 987| mu987_5(int) = InitializeParameter[x] : &:r987_4 +# 987| r987_6(glval) = VariableAddress[y] : +# 987| mu987_7(int) = InitializeParameter[y] : &:r987_6 #-----| Goto -> Block 7 # 988| Block 1 @@ -5556,13 +5445,13 @@ ir.cpp: # 990| Block 2 # 990| r990_1(glval) = VariableAddress[z] : # 990| r990_2(glval) = VariableAddress[x] : -# 990| r990_3(int) = Load : &:r990_2, ~mu987_4 +# 990| r990_3(int) = Load : &:r990_2, ~m? # 990| r990_4(glval) = VariableAddress[y] : -# 990| r990_5(int) = Load : &:r990_4, ~mu987_4 +# 990| r990_5(int) = Load : &:r990_4, ~m? # 990| r990_6(int) = Add : r990_3, r990_5 # 990| mu990_7(int) = Store : &:r990_1, r990_6 # 990| r990_8(glval) = VariableAddress[z] : -# 990| r990_9(int) = Load : &:r990_8, ~mu987_4 +# 990| r990_9(int) = Load : &:r990_8, ~m? # 990| r990_10(int) = Constant[0] : # 990| r990_11(bool) = CompareNE : r990_9, r990_10 # 990| r990_12(bool) = CopyValue : r990_11 @@ -5580,7 +5469,7 @@ ir.cpp: # 992| r992_3(int *) = CopyValue : r992_2 # 992| mu992_4(int *) = Store : &:r992_1, r992_3 # 992| r992_5(glval) = VariableAddress[p] : -# 992| r992_6(int *) = Load : &:r992_5, ~mu987_4 +# 992| r992_6(int *) = Load : &:r992_5, ~m? # 992| r992_7(int *) = Constant[0] : # 992| r992_8(bool) = CompareNE : r992_6, r992_7 # 992| r992_9(bool) = CopyValue : r992_8 @@ -5594,21 +5483,20 @@ ir.cpp: # 994| Block 6 # 994| v994_1(void) = NoOp : -# 987| v987_9(void) = ReturnVoid : -# 987| v987_10(void) = UnmodeledUse : mu* -# 987| v987_11(void) = AliasedUse : ~mu987_4 -# 987| v987_12(void) = ExitFunction : +# 987| v987_8(void) = ReturnVoid : +# 987| v987_9(void) = AliasedUse : ~m? +# 987| v987_10(void) = ExitFunction : # 988| Block 7 # 988| r988_2(glval) = VariableAddress[b] : # 988| r988_3(glval) = VariableAddress[x] : -# 988| r988_4(int) = Load : &:r988_3, ~mu987_4 +# 988| r988_4(int) = Load : &:r988_3, ~m? # 988| r988_5(glval) = VariableAddress[y] : -# 988| r988_6(int) = Load : &:r988_5, ~mu987_4 +# 988| r988_6(int) = Load : &:r988_5, ~m? # 988| r988_7(bool) = CompareLT : r988_4, r988_6 # 988| mu988_8(bool) = Store : &:r988_2, r988_7 # 988| r988_9(glval) = VariableAddress[b] : -# 988| r988_10(bool) = Load : &:r988_9, ~mu987_4 +# 988| r988_10(bool) = Load : &:r988_9, ~m? # 988| r988_11(bool) = CopyValue : r988_10 # 988| v988_12(void) = ConditionalBranch : r988_11 #-----| False -> Block 2 @@ -5619,50 +5507,47 @@ ir.cpp: # 996| v996_1(void) = EnterFunction : # 996| mu996_2(unknown) = AliasedDefinition : # 996| mu996_3(unknown) = InitializeNonLocal : -# 996| mu996_4(unknown) = UnmodeledDefinition : -# 996| r996_5(glval) = VariableAddress[a] : -# 996| mu996_6(int *) = InitializeParameter[a] : &:r996_5 -# 996| r996_7(int *) = Load : &:r996_5, ~mu996_4 -# 996| mu996_8(unknown) = InitializeIndirection[a] : &:r996_7 -# 996| r996_9(glval<..(*)(..)>) = VariableAddress[fn] : -# 996| mu996_10(..(*)(..)) = InitializeParameter[fn] : &:r996_9 +# 996| r996_4(glval) = VariableAddress[a] : +# 996| mu996_5(int *) = InitializeParameter[a] : &:r996_4 +# 996| r996_6(int *) = Load : &:r996_4, ~m? +# 996| mu996_7(unknown) = InitializeIndirection[a] : &:r996_6 +# 996| r996_8(glval<..(*)(..)>) = VariableAddress[fn] : +# 996| mu996_9(..(*)(..)) = InitializeParameter[fn] : &:r996_8 # 997| r997_1(glval) = VariableAddress[#return] : # 997| r997_2(glval) = VariableAddress[a] : -# 997| r997_3(int *) = Load : &:r997_2, ~mu996_4 +# 997| r997_3(int *) = Load : &:r997_2, ~m? # 997| r997_4(int) = Constant[0] : # 997| r997_5(glval) = PointerAdd[4] : r997_3, r997_4 -# 997| r997_6(int) = Load : &:r997_5, ~mu996_4 +# 997| r997_6(int) = Load : &:r997_5, ~m? # 997| r997_7(glval<..(*)(..)>) = VariableAddress[fn] : -# 997| r997_8(..(*)(..)) = Load : &:r997_7, ~mu996_4 +# 997| r997_8(..(*)(..)) = Load : &:r997_7, ~m? # 997| r997_9(float) = Constant[1.0] : # 997| r997_10(int) = Call : func:r997_8, 0:r997_9 -# 997| mu997_11(unknown) = ^CallSideEffect : ~mu996_4 +# 997| mu997_11(unknown) = ^CallSideEffect : ~m? # 997| r997_12(int) = Add : r997_6, r997_10 # 997| mu997_13(int) = Store : &:r997_1, r997_12 -# 996| v996_11(void) = ReturnIndirection[a] : &:r996_7, ~mu996_4 -# 996| r996_12(glval) = VariableAddress[#return] : -# 996| v996_13(void) = ReturnValue : &:r996_12, ~mu996_4 -# 996| v996_14(void) = UnmodeledUse : mu* -# 996| v996_15(void) = AliasedUse : ~mu996_4 -# 996| v996_16(void) = ExitFunction : +# 996| v996_10(void) = ReturnIndirection[a] : &:r996_6, ~m? +# 996| r996_11(glval) = VariableAddress[#return] : +# 996| v996_12(void) = ReturnValue : &:r996_11, ~m? +# 996| v996_13(void) = AliasedUse : ~m? +# 996| v996_14(void) = ExitFunction : # 1000| int ExprStmt(int, int, int) # 1000| Block 0 # 1000| v1000_1(void) = EnterFunction : # 1000| mu1000_2(unknown) = AliasedDefinition : # 1000| mu1000_3(unknown) = InitializeNonLocal : -# 1000| mu1000_4(unknown) = UnmodeledDefinition : -# 1000| r1000_5(glval) = VariableAddress[b] : -# 1000| mu1000_6(int) = InitializeParameter[b] : &:r1000_5 -# 1000| r1000_7(glval) = VariableAddress[y] : -# 1000| mu1000_8(int) = InitializeParameter[y] : &:r1000_7 -# 1000| r1000_9(glval) = VariableAddress[z] : -# 1000| mu1000_10(int) = InitializeParameter[z] : &:r1000_9 +# 1000| r1000_4(glval) = VariableAddress[b] : +# 1000| mu1000_5(int) = InitializeParameter[b] : &:r1000_4 +# 1000| r1000_6(glval) = VariableAddress[y] : +# 1000| mu1000_7(int) = InitializeParameter[y] : &:r1000_6 +# 1000| r1000_8(glval) = VariableAddress[z] : +# 1000| mu1000_9(int) = InitializeParameter[z] : &:r1000_8 # 1001| r1001_1(glval) = VariableAddress[x] : # 1002| r1002_1(glval) = VariableAddress[w] : # 1002| mu1002_2(int) = Uninitialized[w] : &:r1002_1 # 1003| r1003_1(glval) = VariableAddress[b] : -# 1003| r1003_2(int) = Load : &:r1003_1, ~mu1000_4 +# 1003| r1003_2(int) = Load : &:r1003_1, ~m? # 1003| r1003_3(int) = Constant[0] : # 1003| r1003_4(bool) = CompareNE : r1003_2, r1003_3 # 1003| v1003_5(void) = ConditionalBranch : r1003_4 @@ -5671,247 +5556,243 @@ ir.cpp: # 1004| Block 1 # 1004| r1004_1(glval) = VariableAddress[y] : -# 1004| r1004_2(int) = Load : &:r1004_1, ~mu1000_4 +# 1004| r1004_2(int) = Load : &:r1004_1, ~m? # 1004| r1004_3(glval) = VariableAddress[w] : # 1004| mu1004_4(int) = Store : &:r1004_3, r1004_2 #-----| Goto -> Block 3 # 1006| Block 2 # 1006| r1006_1(glval) = VariableAddress[z] : -# 1006| r1006_2(int) = Load : &:r1006_1, ~mu1000_4 +# 1006| r1006_2(int) = Load : &:r1006_1, ~m? # 1006| r1006_3(glval) = VariableAddress[w] : # 1006| mu1006_4(int) = Store : &:r1006_3, r1006_2 #-----| Goto -> Block 3 # 1008| Block 3 # 1008| r1008_1(glval) = VariableAddress[w] : -# 1008| r1008_2(int) = Load : &:r1008_1, ~mu1000_4 +# 1008| r1008_2(int) = Load : &:r1008_1, ~m? # 1001| r1001_2(int) = CopyValue : r1008_2 # 1001| mu1001_3(int) = Store : &:r1001_1, r1001_2 # 1011| r1011_1(glval) = VariableAddress[#return] : # 1011| r1011_2(glval) = VariableAddress[x] : -# 1011| r1011_3(int) = Load : &:r1011_2, ~mu1000_4 +# 1011| r1011_3(int) = Load : &:r1011_2, ~m? # 1011| r1011_4(int) = CopyValue : r1011_3 # 1011| mu1011_5(int) = Store : &:r1011_1, r1011_4 -# 1000| r1000_11(glval) = VariableAddress[#return] : -# 1000| v1000_12(void) = ReturnValue : &:r1000_11, ~mu1000_4 -# 1000| v1000_13(void) = UnmodeledUse : mu* -# 1000| v1000_14(void) = AliasedUse : ~mu1000_4 -# 1000| v1000_15(void) = ExitFunction : +# 1000| r1000_10(glval) = VariableAddress[#return] : +# 1000| v1000_11(void) = ReturnValue : &:r1000_10, ~m? +# 1000| v1000_12(void) = AliasedUse : ~m? +# 1000| v1000_13(void) = ExitFunction : # 1015| void OperatorDelete() # 1015| Block 0 -# 1015| v1015_1(void) = EnterFunction : -# 1015| mu1015_2(unknown) = AliasedDefinition : -# 1015| mu1015_3(unknown) = InitializeNonLocal : -# 1015| mu1015_4(unknown) = UnmodeledDefinition : -# 1016| r1016_1(int *) = Constant[0] : -# 1016| v1016_2(void) = NoOp : -# 1017| r1017_1(String *) = Constant[0] : -# 1017| v1017_2(void) = NoOp : -# 1018| r1018_1(SizedDealloc *) = Constant[0] : -# 1018| v1018_2(void) = NoOp : -# 1019| r1019_1(Overaligned *) = Constant[0] : -# 1019| v1019_2(void) = NoOp : -# 1020| r1020_1(PolymorphicBase *) = Constant[0] : -# 1020| v1020_2(void) = NoOp : -# 1021| v1021_1(void) = NoOp : -# 1015| v1015_5(void) = ReturnVoid : -# 1015| v1015_6(void) = UnmodeledUse : mu* -# 1015| v1015_7(void) = AliasedUse : ~mu1015_4 -# 1015| v1015_8(void) = ExitFunction : +# 1015| v1015_1(void) = EnterFunction : +# 1015| mu1015_2(unknown) = AliasedDefinition : +# 1015| mu1015_3(unknown) = InitializeNonLocal : +# 1016| r1016_1(int *) = Constant[0] : +# 1016| v1016_2(void) = NoOp : +# 1017| r1017_1(String *) = Constant[0] : +# 1017| v1017_2(void) = NoOp : +# 1018| r1018_1(SizedDealloc *) = Constant[0] : +# 1018| v1018_2(void) = NoOp : +# 1019| r1019_1(Overaligned *) = Constant[0] : +# 1019| v1019_2(void) = NoOp : +# 1020| r1020_1(PolymorphicBase *) = Constant[0] : +# 1020| v1020_2(void) = NoOp : +# 1021| v1021_1(void) = NoOp : +# 1015| v1015_4(void) = ReturnVoid : +# 1015| v1015_5(void) = AliasedUse : ~m? +# 1015| v1015_6(void) = ExitFunction : # 1024| void OperatorDeleteArray() # 1024| Block 0 -# 1024| v1024_1(void) = EnterFunction : -# 1024| mu1024_2(unknown) = AliasedDefinition : -# 1024| mu1024_3(unknown) = InitializeNonLocal : -# 1024| mu1024_4(unknown) = UnmodeledDefinition : -# 1025| r1025_1(int *) = Constant[0] : -# 1025| v1025_2(void) = NoOp : -# 1026| r1026_1(String *) = Constant[0] : -# 1026| v1026_2(void) = NoOp : -# 1027| r1027_1(SizedDealloc *) = Constant[0] : -# 1027| v1027_2(void) = NoOp : -# 1028| r1028_1(Overaligned *) = Constant[0] : -# 1028| v1028_2(void) = NoOp : -# 1029| r1029_1(PolymorphicBase *) = Constant[0] : -# 1029| v1029_2(void) = NoOp : -# 1030| v1030_1(void) = NoOp : -# 1024| v1024_5(void) = ReturnVoid : -# 1024| v1024_6(void) = UnmodeledUse : mu* -# 1024| v1024_7(void) = AliasedUse : ~mu1024_4 -# 1024| v1024_8(void) = ExitFunction : +# 1024| v1024_1(void) = EnterFunction : +# 1024| mu1024_2(unknown) = AliasedDefinition : +# 1024| mu1024_3(unknown) = InitializeNonLocal : +# 1025| r1025_1(int *) = Constant[0] : +# 1025| v1025_2(void) = NoOp : +# 1026| r1026_1(String *) = Constant[0] : +# 1026| v1026_2(void) = NoOp : +# 1027| r1027_1(SizedDealloc *) = Constant[0] : +# 1027| v1027_2(void) = NoOp : +# 1028| r1028_1(Overaligned *) = Constant[0] : +# 1028| v1028_2(void) = NoOp : +# 1029| r1029_1(PolymorphicBase *) = Constant[0] : +# 1029| v1029_2(void) = NoOp : +# 1030| v1030_1(void) = NoOp : +# 1024| v1024_4(void) = ReturnVoid : +# 1024| v1024_5(void) = AliasedUse : ~m? +# 1024| v1024_6(void) = ExitFunction : # 1034| void EmptyStructInit() # 1034| Block 0 -# 1034| v1034_1(void) = EnterFunction : -# 1034| mu1034_2(unknown) = AliasedDefinition : -# 1034| mu1034_3(unknown) = InitializeNonLocal : -# 1034| mu1034_4(unknown) = UnmodeledDefinition : -# 1035| r1035_1(glval) = VariableAddress[s] : -# 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 -# 1036| v1036_1(void) = NoOp : -# 1034| v1034_5(void) = ReturnVoid : -# 1034| v1034_6(void) = UnmodeledUse : mu* -# 1034| v1034_7(void) = AliasedUse : ~mu1034_4 -# 1034| v1034_8(void) = ExitFunction : +# 1034| v1034_1(void) = EnterFunction : +# 1034| mu1034_2(unknown) = AliasedDefinition : +# 1034| mu1034_3(unknown) = InitializeNonLocal : +# 1035| r1035_1(glval) = VariableAddress[s] : +# 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 +# 1036| v1036_1(void) = NoOp : +# 1034| v1034_4(void) = ReturnVoid : +# 1034| v1034_5(void) = AliasedUse : ~m? +# 1034| v1034_6(void) = ExitFunction : # 1038| void (lambda [] type at line 1038, col. 12)::operator()() const # 1038| Block 0 -# 1038| v1038_1(void) = EnterFunction : -# 1038| mu1038_2(unknown) = AliasedDefinition : -# 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| mu1038_4(unknown) = UnmodeledDefinition : -# 1038| r1038_5(glval) = InitializeThis : -# 1038| v1038_6(void) = NoOp : -# 1038| v1038_7(void) = ReturnVoid : -# 1038| v1038_8(void) = UnmodeledUse : mu* -# 1038| v1038_9(void) = AliasedUse : ~mu1038_4 -# 1038| v1038_10(void) = ExitFunction : +# 1038| v1038_1(void) = EnterFunction : +# 1038| mu1038_2(unknown) = AliasedDefinition : +# 1038| mu1038_3(unknown) = InitializeNonLocal : +# 1038| r1038_4(glval) = VariableAddress[#this] : +# 1038| mu1038_5(glval) = InitializeParameter[#this] : &:r1038_4 +# 1038| r1038_6(glval) = Load : &:r1038_4, ~m? +# 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 +# 1038| v1038_8(void) = NoOp : +# 1038| v1038_9(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| v1038_10(void) = ReturnVoid : +# 1038| v1038_11(void) = AliasedUse : ~m? +# 1038| v1038_12(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 -# 1038| v1038_1(void) = EnterFunction : -# 1038| mu1038_2(unknown) = AliasedDefinition : -# 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| mu1038_4(unknown) = UnmodeledDefinition : -# 1038| r1038_5(glval) = InitializeThis : -# 1038| r1038_6(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| r1038_7(..(*)(..)) = FunctionAddress[_FUN] : -# 1038| mu1038_8(..(*)(..)) = Store : &:r1038_6, r1038_7 -# 1038| r1038_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_10(void) = ReturnValue : &:r1038_9, ~mu1038_4 -# 1038| v1038_11(void) = UnmodeledUse : mu* -# 1038| v1038_12(void) = AliasedUse : ~mu1038_4 -# 1038| v1038_13(void) = ExitFunction : +# 1038| v1038_1(void) = EnterFunction : +# 1038| mu1038_2(unknown) = AliasedDefinition : +# 1038| mu1038_3(unknown) = InitializeNonLocal : +# 1038| r1038_4(glval) = VariableAddress[#this] : +# 1038| mu1038_5(glval) = InitializeParameter[#this] : &:r1038_4 +# 1038| r1038_6(glval) = Load : &:r1038_4, ~m? +# 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 +# 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| r1038_9(..(*)(..)) = FunctionAddress[_FUN] : +# 1038| mu1038_10(..(*)(..)) = Store : &:r1038_8, r1038_9 +# 1038| v1038_11(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| r1038_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| v1038_13(void) = ReturnValue : &:r1038_12, ~m? +# 1038| v1038_14(void) = AliasedUse : ~m? +# 1038| v1038_15(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 # 1040| v1040_1(void) = EnterFunction : # 1040| mu1040_2(unknown) = AliasedDefinition : # 1040| mu1040_3(unknown) = InitializeNonLocal : -# 1040| mu1040_4(unknown) = UnmodeledDefinition : -# 1040| r1040_5(glval) = VariableAddress[x] : -# 1040| mu1040_6(int) = InitializeParameter[x] : &:r1040_5 -# 1040| r1040_7(glval) = VariableAddress[s] : -# 1040| mu1040_8(String &) = InitializeParameter[s] : &:r1040_7 -# 1040| r1040_9(String &) = Load : &:r1040_7, ~mu1040_4 -# 1040| mu1040_10(unknown) = InitializeIndirection[s] : &:r1040_9 +# 1040| r1040_4(glval) = VariableAddress[x] : +# 1040| mu1040_5(int) = InitializeParameter[x] : &:r1040_4 +# 1040| r1040_6(glval) = VariableAddress[s] : +# 1040| mu1040_7(String &) = InitializeParameter[s] : &:r1040_6 +# 1040| r1040_8(String &) = Load : &:r1040_6, ~m? +# 1040| mu1040_9(unknown) = InitializeIndirection[s] : &:r1040_8 # 1041| r1041_1(glval) = VariableAddress[lambda_empty] : # 1041| r1041_2(glval) = VariableAddress[#temp1041:23] : # 1041| mu1041_3(decltype([...](...){...})) = Uninitialized[#temp1041:23] : &:r1041_2 -# 1041| r1041_4(decltype([...](...){...})) = Load : &:r1041_2, ~mu1040_4 +# 1041| r1041_4(decltype([...](...){...})) = Load : &:r1041_2, ~m? # 1041| mu1041_5(decltype([...](...){...})) = Store : &:r1041_1, r1041_4 # 1042| r1042_1(char) = Constant[65] : # 1043| r1043_1(glval) = VariableAddress[lambda_ref] : # 1043| r1043_2(glval) = VariableAddress[#temp1043:20] : # 1043| mu1043_3(decltype([...](...){...})) = Uninitialized[#temp1043:20] : &:r1043_2 # 1043| r1043_4(glval) = FieldAddress[s] : r1043_2 -#-----| r0_1(glval) = VariableAddress[s] : -#-----| r0_2(String &) = Load : &:r0_1, ~mu1040_4 -# 1043| r1043_5(glval) = CopyValue : r0_2 -# 1043| r1043_6(String &) = CopyValue : r1043_5 -# 1043| mu1043_7(String &) = Store : &:r1043_4, r1043_6 -# 1043| r1043_8(glval) = FieldAddress[x] : r1043_2 -#-----| r0_3(glval) = VariableAddress[x] : -#-----| r0_4(int &) = CopyValue : r0_3 -#-----| mu0_5(int &) = Store : &:r1043_8, r0_4 -# 1043| r1043_9(decltype([...](...){...})) = Load : &:r1043_2, ~mu1040_4 -# 1043| mu1043_10(decltype([...](...){...})) = Store : &:r1043_1, r1043_9 +# 1043| r1043_5(glval) = VariableAddress[s] : +# 1043| r1043_6(String &) = Load : &:r1043_5, ~m? +# 1043| r1043_7(glval) = CopyValue : r1043_6 +# 1043| r1043_8(String &) = CopyValue : r1043_7 +# 1043| mu1043_9(String &) = Store : &:r1043_4, r1043_8 +# 1043| r1043_10(glval) = FieldAddress[x] : r1043_2 +# 1043| r1043_11(glval) = VariableAddress[x] : +#-----| r0_1(int &) = CopyValue : r1043_11 +#-----| mu0_2(int &) = Store : &:r1043_10, r0_1 +# 1043| r1043_12(decltype([...](...){...})) = Load : &:r1043_2, ~m? +# 1043| mu1043_13(decltype([...](...){...})) = Store : &:r1043_1, r1043_12 # 1044| r1044_1(glval) = VariableAddress[lambda_ref] : # 1044| r1044_2(glval) = Convert : r1044_1 # 1044| r1044_3(glval) = FunctionAddress[operator()] : # 1044| r1044_4(float) = Constant[1.0] : # 1044| r1044_5(char) = Call : func:r1044_3, this:r1044_2, 0:r1044_4 -# 1044| mu1044_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1044| v1044_7(void) = ^BufferReadSideEffect[-1] : &:r1044_2, ~mu1040_4 +# 1044| mu1044_6(unknown) = ^CallSideEffect : ~m? +# 1044| v1044_7(void) = ^BufferReadSideEffect[-1] : &:r1044_2, ~m? # 1044| mu1044_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1044_2 # 1045| r1045_1(glval) = VariableAddress[lambda_val] : # 1045| r1045_2(glval) = VariableAddress[#temp1045:20] : # 1045| mu1045_3(decltype([...](...){...})) = Uninitialized[#temp1045:20] : &:r1045_2 # 1045| r1045_4(glval) = FieldAddress[s] : r1045_2 -#-----| r0_6(glval) = FunctionAddress[String] : -#-----| v0_7(void) = Call : func:r0_6, this:r1045_4 -#-----| mu0_8(unknown) = ^CallSideEffect : ~mu1040_4 -#-----| mu0_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_4 -# 1045| r1045_5(glval) = FieldAddress[x] : r1045_2 -#-----| r0_10(glval) = VariableAddress[x] : -#-----| r0_11(int) = Load : &:r0_10, ~mu1040_4 -#-----| mu0_12(int) = Store : &:r1045_5, r0_11 -# 1045| r1045_6(decltype([...](...){...})) = Load : &:r1045_2, ~mu1040_4 -# 1045| mu1045_7(decltype([...](...){...})) = Store : &:r1045_1, r1045_6 +# 1045| r1045_5(glval) = FunctionAddress[String] : +# 1045| v1045_6(void) = Call : func:r1045_5, this:r1045_4 +# 1045| mu1045_7(unknown) = ^CallSideEffect : ~m? +# 1045| mu1045_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_4 +# 1045| r1045_9(glval) = FieldAddress[x] : r1045_2 +# 1045| r1045_10(glval) = VariableAddress[x] : +# 1045| r1045_11(int) = Load : &:r1045_10, ~m? +# 1045| mu1045_12(int) = Store : &:r1045_9, r1045_11 +# 1045| r1045_13(decltype([...](...){...})) = Load : &:r1045_2, ~m? +# 1045| mu1045_14(decltype([...](...){...})) = Store : &:r1045_1, r1045_13 # 1046| r1046_1(glval) = VariableAddress[lambda_val] : # 1046| r1046_2(glval) = Convert : r1046_1 # 1046| r1046_3(glval) = FunctionAddress[operator()] : # 1046| r1046_4(float) = Constant[2.0] : # 1046| r1046_5(char) = Call : func:r1046_3, this:r1046_2, 0:r1046_4 -# 1046| mu1046_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1046| v1046_7(void) = ^BufferReadSideEffect[-1] : &:r1046_2, ~mu1040_4 +# 1046| mu1046_6(unknown) = ^CallSideEffect : ~m? +# 1046| v1046_7(void) = ^BufferReadSideEffect[-1] : &:r1046_2, ~m? # 1046| mu1046_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1046_2 # 1047| r1047_1(glval) = VariableAddress[lambda_ref_explicit] : # 1047| r1047_2(glval) = VariableAddress[#temp1047:29] : # 1047| mu1047_3(decltype([...](...){...})) = Uninitialized[#temp1047:29] : &:r1047_2 # 1047| r1047_4(glval) = FieldAddress[s] : r1047_2 # 1047| r1047_5(glval) = VariableAddress[s] : -# 1047| r1047_6(String &) = Load : &:r1047_5, ~mu1040_4 +# 1047| r1047_6(String &) = Load : &:r1047_5, ~m? # 1047| r1047_7(glval) = CopyValue : r1047_6 # 1047| r1047_8(String &) = CopyValue : r1047_7 # 1047| mu1047_9(String &) = Store : &:r1047_4, r1047_8 -# 1047| r1047_10(decltype([...](...){...})) = Load : &:r1047_2, ~mu1040_4 +# 1047| r1047_10(decltype([...](...){...})) = Load : &:r1047_2, ~m? # 1047| mu1047_11(decltype([...](...){...})) = Store : &:r1047_1, r1047_10 # 1048| r1048_1(glval) = VariableAddress[lambda_ref_explicit] : # 1048| r1048_2(glval) = Convert : r1048_1 # 1048| r1048_3(glval) = FunctionAddress[operator()] : # 1048| r1048_4(float) = Constant[3.0] : # 1048| r1048_5(char) = Call : func:r1048_3, this:r1048_2, 0:r1048_4 -# 1048| mu1048_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1048| v1048_7(void) = ^BufferReadSideEffect[-1] : &:r1048_2, ~mu1040_4 +# 1048| mu1048_6(unknown) = ^CallSideEffect : ~m? +# 1048| v1048_7(void) = ^BufferReadSideEffect[-1] : &:r1048_2, ~m? # 1048| mu1048_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1048_2 # 1049| r1049_1(glval) = VariableAddress[lambda_val_explicit] : # 1049| r1049_2(glval) = VariableAddress[#temp1049:29] : # 1049| mu1049_3(decltype([...](...){...})) = Uninitialized[#temp1049:29] : &:r1049_2 # 1049| r1049_4(glval) = FieldAddress[s] : r1049_2 -#-----| r0_13(glval) = FunctionAddress[String] : -#-----| v0_14(void) = Call : func:r0_13, this:r1049_4 -#-----| mu0_15(unknown) = ^CallSideEffect : ~mu1040_4 -#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_4 -# 1049| r1049_5(decltype([...](...){...})) = Load : &:r1049_2, ~mu1040_4 -# 1049| mu1049_6(decltype([...](...){...})) = Store : &:r1049_1, r1049_5 +# 1049| r1049_5(glval) = FunctionAddress[String] : +# 1049| v1049_6(void) = Call : func:r1049_5, this:r1049_4 +# 1049| mu1049_7(unknown) = ^CallSideEffect : ~m? +# 1049| mu1049_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_4 +# 1049| r1049_9(decltype([...](...){...})) = Load : &:r1049_2, ~m? +# 1049| mu1049_10(decltype([...](...){...})) = Store : &:r1049_1, r1049_9 # 1050| r1050_1(glval) = VariableAddress[lambda_val_explicit] : # 1050| r1050_2(glval) = Convert : r1050_1 # 1050| r1050_3(glval) = FunctionAddress[operator()] : # 1050| r1050_4(float) = Constant[4.0] : # 1050| r1050_5(char) = Call : func:r1050_3, this:r1050_2, 0:r1050_4 -# 1050| mu1050_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1050| v1050_7(void) = ^BufferReadSideEffect[-1] : &:r1050_2, ~mu1040_4 +# 1050| mu1050_6(unknown) = ^CallSideEffect : ~m? +# 1050| v1050_7(void) = ^BufferReadSideEffect[-1] : &:r1050_2, ~m? # 1050| mu1050_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1050_2 # 1051| r1051_1(glval) = VariableAddress[lambda_mixed_explicit] : # 1051| r1051_2(glval) = VariableAddress[#temp1051:31] : # 1051| mu1051_3(decltype([...](...){...})) = Uninitialized[#temp1051:31] : &:r1051_2 # 1051| r1051_4(glval) = FieldAddress[s] : r1051_2 # 1051| r1051_5(glval) = VariableAddress[s] : -# 1051| r1051_6(String &) = Load : &:r1051_5, ~mu1040_4 +# 1051| r1051_6(String &) = Load : &:r1051_5, ~m? # 1051| r1051_7(glval) = CopyValue : r1051_6 # 1051| r1051_8(String &) = CopyValue : r1051_7 # 1051| mu1051_9(String &) = Store : &:r1051_4, r1051_8 # 1051| r1051_10(glval) = FieldAddress[x] : r1051_2 # 1051| r1051_11(glval) = VariableAddress[x] : -# 1051| r1051_12(int) = Load : &:r1051_11, ~mu1040_4 +# 1051| r1051_12(int) = Load : &:r1051_11, ~m? # 1051| mu1051_13(int) = Store : &:r1051_10, r1051_12 -# 1051| r1051_14(decltype([...](...){...})) = Load : &:r1051_2, ~mu1040_4 +# 1051| r1051_14(decltype([...](...){...})) = Load : &:r1051_2, ~m? # 1051| mu1051_15(decltype([...](...){...})) = Store : &:r1051_1, r1051_14 # 1052| r1052_1(glval) = VariableAddress[lambda_mixed_explicit] : # 1052| r1052_2(glval) = Convert : r1052_1 # 1052| r1052_3(glval) = FunctionAddress[operator()] : # 1052| r1052_4(float) = Constant[5.0] : # 1052| r1052_5(char) = Call : func:r1052_3, this:r1052_2, 0:r1052_4 -# 1052| mu1052_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1052| v1052_7(void) = ^BufferReadSideEffect[-1] : &:r1052_2, ~mu1040_4 +# 1052| mu1052_6(unknown) = ^CallSideEffect : ~m? +# 1052| v1052_7(void) = ^BufferReadSideEffect[-1] : &:r1052_2, ~m? # 1052| mu1052_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1052_2 # 1053| r1053_1(glval) = VariableAddress[r] : # 1053| r1053_2(glval) = VariableAddress[x] : -# 1053| r1053_3(int) = Load : &:r1053_2, ~mu1040_4 +# 1053| r1053_3(int) = Load : &:r1053_2, ~m? # 1053| r1053_4(int) = Constant[1] : # 1053| r1053_5(int) = Sub : r1053_3, r1053_4 # 1053| mu1053_6(int) = Store : &:r1053_1, r1053_5 @@ -5920,17 +5801,17 @@ ir.cpp: # 1054| mu1054_3(decltype([...](...){...})) = Uninitialized[#temp1054:22] : &:r1054_2 # 1054| r1054_4(glval) = FieldAddress[s] : r1054_2 # 1054| r1054_5(glval) = VariableAddress[s] : -# 1054| r1054_6(String &) = Load : &:r1054_5, ~mu1040_4 +# 1054| r1054_6(String &) = Load : &:r1054_5, ~m? # 1054| r1054_7(glval) = CopyValue : r1054_6 # 1054| r1054_8(String &) = CopyValue : r1054_7 # 1054| mu1054_9(String &) = Store : &:r1054_4, r1054_8 # 1054| r1054_10(glval) = FieldAddress[x] : r1054_2 # 1054| r1054_11(glval) = VariableAddress[x] : -# 1054| r1054_12(int) = Load : &:r1054_11, ~mu1040_4 +# 1054| r1054_12(int) = Load : &:r1054_11, ~m? # 1054| mu1054_13(int) = Store : &:r1054_10, r1054_12 # 1054| r1054_14(glval) = FieldAddress[i] : r1054_2 # 1054| r1054_15(glval) = VariableAddress[x] : -# 1054| r1054_16(int) = Load : &:r1054_15, ~mu1040_4 +# 1054| r1054_16(int) = Load : &:r1054_15, ~m? # 1054| r1054_17(int) = Constant[1] : # 1054| r1054_18(int) = Add : r1054_16, r1054_17 # 1054| mu1054_19(int) = Store : &:r1054_14, r1054_18 @@ -5938,360 +5819,390 @@ ir.cpp: # 1054| r1054_21(glval) = VariableAddress[r] : # 1054| r1054_22(int &) = CopyValue : r1054_21 # 1054| mu1054_23(int &) = Store : &:r1054_20, r1054_22 -# 1054| r1054_24(decltype([...](...){...})) = Load : &:r1054_2, ~mu1040_4 +# 1054| r1054_24(decltype([...](...){...})) = Load : &:r1054_2, ~m? # 1054| mu1054_25(decltype([...](...){...})) = Store : &:r1054_1, r1054_24 # 1055| r1055_1(glval) = VariableAddress[lambda_inits] : # 1055| r1055_2(glval) = Convert : r1055_1 # 1055| r1055_3(glval) = FunctionAddress[operator()] : # 1055| r1055_4(float) = Constant[6.0] : # 1055| r1055_5(char) = Call : func:r1055_3, this:r1055_2, 0:r1055_4 -# 1055| mu1055_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~mu1040_4 +# 1055| mu1055_6(unknown) = ^CallSideEffect : ~m? +# 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~m? # 1055| mu1055_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1055_2 # 1056| v1056_1(void) = NoOp : -# 1040| v1040_11(void) = ReturnIndirection[s] : &:r1040_9, ~mu1040_4 -# 1040| v1040_12(void) = ReturnVoid : -# 1040| v1040_13(void) = UnmodeledUse : mu* -# 1040| v1040_14(void) = AliasedUse : ~mu1040_4 -# 1040| v1040_15(void) = ExitFunction : +# 1040| v1040_10(void) = ReturnIndirection[s] : &:r1040_8, ~m? +# 1040| v1040_11(void) = ReturnVoid : +# 1040| v1040_12(void) = AliasedUse : ~m? +# 1040| v1040_13(void) = ExitFunction : # 1041| char (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator()(float) const # 1041| Block 0 -# 1041| v1041_1(void) = EnterFunction : -# 1041| mu1041_2(unknown) = AliasedDefinition : -# 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| mu1041_4(unknown) = UnmodeledDefinition : -# 1041| r1041_5(glval) = InitializeThis : -# 1041| r1041_6(glval) = VariableAddress[f] : -# 1041| mu1041_7(float) = InitializeParameter[f] : &:r1041_6 -# 1041| r1041_8(glval) = VariableAddress[#return] : -# 1041| r1041_9(char) = Constant[65] : -# 1041| mu1041_10(char) = Store : &:r1041_8, r1041_9 -# 1041| r1041_11(glval) = VariableAddress[#return] : -# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~mu1041_4 -# 1041| v1041_13(void) = UnmodeledUse : mu* -# 1041| v1041_14(void) = AliasedUse : ~mu1041_4 -# 1041| v1041_15(void) = ExitFunction : +# 1041| v1041_1(void) = EnterFunction : +# 1041| mu1041_2(unknown) = AliasedDefinition : +# 1041| mu1041_3(unknown) = InitializeNonLocal : +# 1041| r1041_4(glval) = VariableAddress[#this] : +# 1041| mu1041_5(glval) = InitializeParameter[#this] : &:r1041_4 +# 1041| r1041_6(glval) = Load : &:r1041_4, ~m? +# 1041| mu1041_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1041_6 +# 1041| r1041_8(glval) = VariableAddress[f] : +# 1041| mu1041_9(float) = InitializeParameter[f] : &:r1041_8 +# 1041| r1041_10(glval) = VariableAddress[#return] : +# 1041| r1041_11(char) = Constant[65] : +# 1041| mu1041_12(char) = Store : &:r1041_10, r1041_11 +# 1041| v1041_13(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_14(glval) = VariableAddress[#return] : +# 1041| v1041_15(void) = ReturnValue : &:r1041_14, ~m? +# 1041| v1041_16(void) = AliasedUse : ~m? +# 1041| v1041_17(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 -# 1041| v1041_1(void) = EnterFunction : -# 1041| mu1041_2(unknown) = AliasedDefinition : -# 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| mu1041_4(unknown) = UnmodeledDefinition : -# 1041| r1041_5(glval) = InitializeThis : -# 1041| r1041_6(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| r1041_7(..(*)(..)) = FunctionAddress[_FUN] : -# 1041| mu1041_8(..(*)(..)) = Store : &:r1041_6, r1041_7 -# 1041| r1041_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_10(void) = ReturnValue : &:r1041_9, ~mu1041_4 -# 1041| v1041_11(void) = UnmodeledUse : mu* -# 1041| v1041_12(void) = AliasedUse : ~mu1041_4 -# 1041| v1041_13(void) = ExitFunction : +# 1041| v1041_1(void) = EnterFunction : +# 1041| mu1041_2(unknown) = AliasedDefinition : +# 1041| mu1041_3(unknown) = InitializeNonLocal : +# 1041| r1041_4(glval) = VariableAddress[#this] : +# 1041| mu1041_5(glval) = InitializeParameter[#this] : &:r1041_4 +# 1041| r1041_6(glval) = Load : &:r1041_4, ~m? +# 1041| mu1041_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1041_6 +# 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| r1041_9(..(*)(..)) = FunctionAddress[_FUN] : +# 1041| mu1041_10(..(*)(..)) = Store : &:r1041_8, r1041_9 +# 1041| v1041_11(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| v1041_13(void) = ReturnValue : &:r1041_12, ~m? +# 1041| v1041_14(void) = AliasedUse : ~m? +# 1041| v1041_15(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 -# 1043| v1043_1(void) = EnterFunction : -# 1043| mu1043_2(unknown) = AliasedDefinition : -# 1043| mu1043_3(unknown) = InitializeNonLocal : -# 1043| mu1043_4(unknown) = UnmodeledDefinition : -# 1043| r1043_5(glval) = InitializeThis : -# 1043| r1043_6(glval) = VariableAddress[f] : -# 1043| mu1043_7(float) = InitializeParameter[f] : &:r1043_6 -# 1043| r1043_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1043_4 -# 1043| r1043_9(glval) = CopyValue : r0_3 -# 1043| r1043_10(glval) = FunctionAddress[c_str] : -# 1043| r1043_11(char *) = Call : func:r1043_10, this:r1043_9 -# 1043| mu1043_12(unknown) = ^CallSideEffect : ~mu1043_4 -# 1043| v1043_13(void) = ^BufferReadSideEffect[-1] : &:r1043_9, ~mu1043_4 -# 1043| mu1043_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_9 -#-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int &) = Load : &:r0_5, ~mu1043_4 -# 1043| r1043_15(int) = Load : &:r0_6, ~mu1043_4 -# 1043| r1043_16(glval) = PointerAdd[1] : r1043_11, r1043_15 -# 1043| r1043_17(char) = Load : &:r1043_16, ~mu1043_4 -# 1043| mu1043_18(char) = Store : &:r1043_8, r1043_17 -# 1043| r1043_19(glval) = VariableAddress[#return] : -# 1043| v1043_20(void) = ReturnValue : &:r1043_19, ~mu1043_4 -# 1043| v1043_21(void) = UnmodeledUse : mu* -# 1043| v1043_22(void) = AliasedUse : ~mu1043_4 -# 1043| v1043_23(void) = ExitFunction : +# 1043| v1043_1(void) = EnterFunction : +# 1043| mu1043_2(unknown) = AliasedDefinition : +# 1043| mu1043_3(unknown) = InitializeNonLocal : +# 1043| r1043_4(glval) = VariableAddress[#this] : +# 1043| mu1043_5(glval) = InitializeParameter[#this] : &:r1043_4 +# 1043| r1043_6(glval) = Load : &:r1043_4, ~m? +# 1043| mu1043_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1043_6 +# 1043| r1043_8(glval) = VariableAddress[f] : +# 1043| mu1043_9(float) = InitializeParameter[f] : &:r1043_8 +# 1043| r1043_10(glval) = VariableAddress[#return] : +# 1043| r1043_11(glval) = VariableAddress[#this] : +# 1043| r1043_12(lambda [] type at line 1043, col. 21 *) = Load : &:r1043_11, ~m? +# 1043| r1043_13(glval) = FieldAddress[s] : r1043_12 +# 1043| r1043_14(String &) = Load : &:r1043_13, ~m? +# 1043| r1043_15(glval) = CopyValue : r1043_14 +# 1043| r1043_16(glval) = FunctionAddress[c_str] : +# 1043| r1043_17(char *) = Call : func:r1043_16, this:r1043_15 +# 1043| mu1043_18(unknown) = ^CallSideEffect : ~m? +# 1043| v1043_19(void) = ^BufferReadSideEffect[-1] : &:r1043_15, ~m? +# 1043| mu1043_20(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_15 +# 1043| r1043_21(glval) = VariableAddress[#this] : +# 1043| r1043_22(lambda [] type at line 1043, col. 21 *) = Load : &:r1043_21, ~m? +# 1043| r1043_23(glval) = FieldAddress[x] : r1043_22 +# 1043| r1043_24(int &) = Load : &:r1043_23, ~m? +# 1043| r1043_25(int) = Load : &:r1043_24, ~m? +# 1043| r1043_26(glval) = PointerAdd[1] : r1043_17, r1043_25 +# 1043| r1043_27(char) = Load : &:r1043_26, ~m? +# 1043| mu1043_28(char) = Store : &:r1043_10, r1043_27 +# 1043| v1043_29(void) = ReturnIndirection[#this] : &:r1043_6, ~m? +# 1043| r1043_30(glval) = VariableAddress[#return] : +# 1043| v1043_31(void) = ReturnValue : &:r1043_30, ~m? +# 1043| v1043_32(void) = AliasedUse : ~m? +# 1043| v1043_33(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 -# 1045| v1045_1(void) = EnterFunction : -# 1045| mu1045_2(unknown) = AliasedDefinition : -# 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| mu1045_4(unknown) = UnmodeledDefinition : -# 1045| r1045_5(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 1045| r1045_6(glval) = FieldAddress[s] : r1045_5 -# 1045| r1045_7(glval) = FunctionAddress[~String] : -# 1045| v1045_8(void) = Call : func:r1045_7, this:r1045_6 -# 1045| mu1045_9(unknown) = ^CallSideEffect : ~mu1045_4 -# 1045| v1045_10(void) = ReturnVoid : -# 1045| v1045_11(void) = UnmodeledUse : mu* -# 1045| v1045_12(void) = AliasedUse : ~mu1045_4 -# 1045| v1045_13(void) = ExitFunction : +# 1045| v1045_1(void) = EnterFunction : +# 1045| mu1045_2(unknown) = AliasedDefinition : +# 1045| mu1045_3(unknown) = InitializeNonLocal : +# 1045| r1045_4(glval) = VariableAddress[#this] : +# 1045| mu1045_5(glval) = InitializeParameter[#this] : &:r1045_4 +# 1045| r1045_6(glval) = Load : &:r1045_4, ~m? +# 1045| mu1045_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1045_6 +#-----| v0_1(void) = NoOp : +# 1045| r1045_8(glval) = FieldAddress[s] : mu1045_5 +# 1045| r1045_9(glval) = FunctionAddress[~String] : +# 1045| v1045_10(void) = Call : func:r1045_9, this:r1045_8 +# 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? +# 1045| v1045_12(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| v1045_13(void) = ReturnVoid : +# 1045| v1045_14(void) = AliasedUse : ~m? +# 1045| v1045_15(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 -# 1045| v1045_1(void) = EnterFunction : -# 1045| mu1045_2(unknown) = AliasedDefinition : -# 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| mu1045_4(unknown) = UnmodeledDefinition : -# 1045| r1045_5(glval) = InitializeThis : -# 1045| r1045_6(glval) = VariableAddress[f] : -# 1045| mu1045_7(float) = InitializeParameter[f] : &:r1045_6 -# 1045| r1045_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1045| r1045_9(glval) = FunctionAddress[c_str] : -# 1045| r1045_10(char *) = Call : func:r1045_9, this:r0_2 -# 1045| mu1045_11(unknown) = ^CallSideEffect : ~mu1045_4 -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~mu1045_4 -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -#-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_5 -#-----| r0_6(glval) = FieldAddress[x] : r0_5 -#-----| r0_7(int) = Load : &:r0_6, ~mu1045_4 -# 1045| r1045_12(glval) = PointerAdd[1] : r1045_10, r0_7 -# 1045| r1045_13(char) = Load : &:r1045_12, ~mu1045_4 -# 1045| mu1045_14(char) = Store : &:r1045_8, r1045_13 -# 1045| r1045_15(glval) = VariableAddress[#return] : -# 1045| v1045_16(void) = ReturnValue : &:r1045_15, ~mu1045_4 -# 1045| v1045_17(void) = UnmodeledUse : mu* -# 1045| v1045_18(void) = AliasedUse : ~mu1045_4 -# 1045| v1045_19(void) = ExitFunction : +# 1045| v1045_1(void) = EnterFunction : +# 1045| mu1045_2(unknown) = AliasedDefinition : +# 1045| mu1045_3(unknown) = InitializeNonLocal : +# 1045| r1045_4(glval) = VariableAddress[#this] : +# 1045| mu1045_5(glval) = InitializeParameter[#this] : &:r1045_4 +# 1045| r1045_6(glval) = Load : &:r1045_4, ~m? +# 1045| mu1045_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1045_6 +# 1045| r1045_8(glval) = VariableAddress[f] : +# 1045| mu1045_9(float) = InitializeParameter[f] : &:r1045_8 +# 1045| r1045_10(glval) = VariableAddress[#return] : +# 1045| r1045_11(glval) = VariableAddress[#this] : +# 1045| r1045_12(lambda [] type at line 1045, col. 21 *) = Load : &:r1045_11, ~m? +# 1045| r1045_13(glval) = FieldAddress[s] : r1045_12 +# 1045| r1045_14(glval) = FunctionAddress[c_str] : +# 1045| r1045_15(char *) = Call : func:r1045_14, this:r1045_13 +# 1045| mu1045_16(unknown) = ^CallSideEffect : ~m? +# 1045| v1045_17(void) = ^BufferReadSideEffect[-1] : &:r1045_13, ~m? +# 1045| mu1045_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_13 +# 1045| r1045_19(glval) = VariableAddress[#this] : +# 1045| r1045_20(lambda [] type at line 1045, col. 21 *) = Load : &:r1045_19, ~m? +# 1045| r1045_21(glval) = FieldAddress[x] : r1045_20 +# 1045| r1045_22(int) = Load : &:r1045_21, ~m? +# 1045| r1045_23(glval) = PointerAdd[1] : r1045_15, r1045_22 +# 1045| r1045_24(char) = Load : &:r1045_23, ~m? +# 1045| mu1045_25(char) = Store : &:r1045_10, r1045_24 +# 1045| v1045_26(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| r1045_27(glval) = VariableAddress[#return] : +# 1045| v1045_28(void) = ReturnValue : &:r1045_27, ~m? +# 1045| v1045_29(void) = AliasedUse : ~m? +# 1045| v1045_30(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 -# 1047| v1047_1(void) = EnterFunction : -# 1047| mu1047_2(unknown) = AliasedDefinition : -# 1047| mu1047_3(unknown) = InitializeNonLocal : -# 1047| mu1047_4(unknown) = UnmodeledDefinition : -# 1047| r1047_5(glval) = InitializeThis : -# 1047| r1047_6(glval) = VariableAddress[f] : -# 1047| mu1047_7(float) = InitializeParameter[f] : &:r1047_6 -# 1047| r1047_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1047_4 -# 1047| r1047_9(glval) = CopyValue : r0_3 -# 1047| r1047_10(glval) = FunctionAddress[c_str] : -# 1047| r1047_11(char *) = Call : func:r1047_10, this:r1047_9 -# 1047| mu1047_12(unknown) = ^CallSideEffect : ~mu1047_4 -# 1047| v1047_13(void) = ^BufferReadSideEffect[-1] : &:r1047_9, ~mu1047_4 -# 1047| mu1047_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_9 -# 1047| r1047_15(int) = Constant[0] : -# 1047| r1047_16(glval) = PointerAdd[1] : r1047_11, r1047_15 -# 1047| r1047_17(char) = Load : &:r1047_16, ~mu1047_4 -# 1047| mu1047_18(char) = Store : &:r1047_8, r1047_17 -# 1047| r1047_19(glval) = VariableAddress[#return] : -# 1047| v1047_20(void) = ReturnValue : &:r1047_19, ~mu1047_4 -# 1047| v1047_21(void) = UnmodeledUse : mu* -# 1047| v1047_22(void) = AliasedUse : ~mu1047_4 -# 1047| v1047_23(void) = ExitFunction : +# 1047| v1047_1(void) = EnterFunction : +# 1047| mu1047_2(unknown) = AliasedDefinition : +# 1047| mu1047_3(unknown) = InitializeNonLocal : +# 1047| r1047_4(glval) = VariableAddress[#this] : +# 1047| mu1047_5(glval) = InitializeParameter[#this] : &:r1047_4 +# 1047| r1047_6(glval) = Load : &:r1047_4, ~m? +# 1047| mu1047_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1047_6 +# 1047| r1047_8(glval) = VariableAddress[f] : +# 1047| mu1047_9(float) = InitializeParameter[f] : &:r1047_8 +# 1047| r1047_10(glval) = VariableAddress[#return] : +# 1047| r1047_11(glval) = VariableAddress[#this] : +# 1047| r1047_12(lambda [] type at line 1047, col. 30 *) = Load : &:r1047_11, ~m? +# 1047| r1047_13(glval) = FieldAddress[s] : r1047_12 +# 1047| r1047_14(String &) = Load : &:r1047_13, ~m? +# 1047| r1047_15(glval) = CopyValue : r1047_14 +# 1047| r1047_16(glval) = FunctionAddress[c_str] : +# 1047| r1047_17(char *) = Call : func:r1047_16, this:r1047_15 +# 1047| mu1047_18(unknown) = ^CallSideEffect : ~m? +# 1047| v1047_19(void) = ^BufferReadSideEffect[-1] : &:r1047_15, ~m? +# 1047| mu1047_20(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_15 +# 1047| r1047_21(int) = Constant[0] : +# 1047| r1047_22(glval) = PointerAdd[1] : r1047_17, r1047_21 +# 1047| r1047_23(char) = Load : &:r1047_22, ~m? +# 1047| mu1047_24(char) = Store : &:r1047_10, r1047_23 +# 1047| v1047_25(void) = ReturnIndirection[#this] : &:r1047_6, ~m? +# 1047| r1047_26(glval) = VariableAddress[#return] : +# 1047| v1047_27(void) = ReturnValue : &:r1047_26, ~m? +# 1047| v1047_28(void) = AliasedUse : ~m? +# 1047| v1047_29(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 -# 1049| v1049_1(void) = EnterFunction : -# 1049| mu1049_2(unknown) = AliasedDefinition : -# 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| mu1049_4(unknown) = UnmodeledDefinition : -# 1049| r1049_5(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 1049| r1049_6(glval) = FieldAddress[s] : r1049_5 -# 1049| r1049_7(glval) = FunctionAddress[~String] : -# 1049| v1049_8(void) = Call : func:r1049_7, this:r1049_6 -# 1049| mu1049_9(unknown) = ^CallSideEffect : ~mu1049_4 -# 1049| v1049_10(void) = ReturnVoid : -# 1049| v1049_11(void) = UnmodeledUse : mu* -# 1049| v1049_12(void) = AliasedUse : ~mu1049_4 -# 1049| v1049_13(void) = ExitFunction : +# 1049| v1049_1(void) = EnterFunction : +# 1049| mu1049_2(unknown) = AliasedDefinition : +# 1049| mu1049_3(unknown) = InitializeNonLocal : +# 1049| r1049_4(glval) = VariableAddress[#this] : +# 1049| mu1049_5(glval) = InitializeParameter[#this] : &:r1049_4 +# 1049| r1049_6(glval) = Load : &:r1049_4, ~m? +# 1049| mu1049_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1049_6 +#-----| v0_1(void) = NoOp : +# 1049| r1049_8(glval) = FieldAddress[s] : mu1049_5 +# 1049| r1049_9(glval) = FunctionAddress[~String] : +# 1049| v1049_10(void) = Call : func:r1049_9, this:r1049_8 +# 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? +# 1049| v1049_12(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| v1049_13(void) = ReturnVoid : +# 1049| v1049_14(void) = AliasedUse : ~m? +# 1049| v1049_15(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 -# 1049| v1049_1(void) = EnterFunction : -# 1049| mu1049_2(unknown) = AliasedDefinition : -# 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| mu1049_4(unknown) = UnmodeledDefinition : -# 1049| r1049_5(glval) = InitializeThis : -# 1049| r1049_6(glval) = VariableAddress[f] : -# 1049| mu1049_7(float) = InitializeParameter[f] : &:r1049_6 -# 1049| r1049_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1049| r1049_9(glval) = FunctionAddress[c_str] : -# 1049| r1049_10(char *) = Call : func:r1049_9, this:r0_2 -# 1049| mu1049_11(unknown) = ^CallSideEffect : ~mu1049_4 -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~mu1049_4 -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -# 1049| r1049_12(int) = Constant[0] : -# 1049| r1049_13(glval) = PointerAdd[1] : r1049_10, r1049_12 -# 1049| r1049_14(char) = Load : &:r1049_13, ~mu1049_4 -# 1049| mu1049_15(char) = Store : &:r1049_8, r1049_14 -# 1049| r1049_16(glval) = VariableAddress[#return] : -# 1049| v1049_17(void) = ReturnValue : &:r1049_16, ~mu1049_4 -# 1049| v1049_18(void) = UnmodeledUse : mu* -# 1049| v1049_19(void) = AliasedUse : ~mu1049_4 -# 1049| v1049_20(void) = ExitFunction : +# 1049| v1049_1(void) = EnterFunction : +# 1049| mu1049_2(unknown) = AliasedDefinition : +# 1049| mu1049_3(unknown) = InitializeNonLocal : +# 1049| r1049_4(glval) = VariableAddress[#this] : +# 1049| mu1049_5(glval) = InitializeParameter[#this] : &:r1049_4 +# 1049| r1049_6(glval) = Load : &:r1049_4, ~m? +# 1049| mu1049_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1049_6 +# 1049| r1049_8(glval) = VariableAddress[f] : +# 1049| mu1049_9(float) = InitializeParameter[f] : &:r1049_8 +# 1049| r1049_10(glval) = VariableAddress[#return] : +# 1049| r1049_11(glval) = VariableAddress[#this] : +# 1049| r1049_12(lambda [] type at line 1049, col. 30 *) = Load : &:r1049_11, ~m? +# 1049| r1049_13(glval) = FieldAddress[s] : r1049_12 +# 1049| r1049_14(glval) = FunctionAddress[c_str] : +# 1049| r1049_15(char *) = Call : func:r1049_14, this:r1049_13 +# 1049| mu1049_16(unknown) = ^CallSideEffect : ~m? +# 1049| v1049_17(void) = ^BufferReadSideEffect[-1] : &:r1049_13, ~m? +# 1049| mu1049_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_13 +# 1049| r1049_19(int) = Constant[0] : +# 1049| r1049_20(glval) = PointerAdd[1] : r1049_15, r1049_19 +# 1049| r1049_21(char) = Load : &:r1049_20, ~m? +# 1049| mu1049_22(char) = Store : &:r1049_10, r1049_21 +# 1049| v1049_23(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| r1049_24(glval) = VariableAddress[#return] : +# 1049| v1049_25(void) = ReturnValue : &:r1049_24, ~m? +# 1049| v1049_26(void) = AliasedUse : ~m? +# 1049| v1049_27(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 -# 1051| v1051_1(void) = EnterFunction : -# 1051| mu1051_2(unknown) = AliasedDefinition : -# 1051| mu1051_3(unknown) = InitializeNonLocal : -# 1051| mu1051_4(unknown) = UnmodeledDefinition : -# 1051| r1051_5(glval) = InitializeThis : -# 1051| r1051_6(glval) = VariableAddress[f] : -# 1051| mu1051_7(float) = InitializeParameter[f] : &:r1051_6 -# 1051| r1051_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1051_4 -# 1051| r1051_9(glval) = CopyValue : r0_3 -# 1051| r1051_10(glval) = FunctionAddress[c_str] : -# 1051| r1051_11(char *) = Call : func:r1051_10, this:r1051_9 -# 1051| mu1051_12(unknown) = ^CallSideEffect : ~mu1051_4 -# 1051| v1051_13(void) = ^BufferReadSideEffect[-1] : &:r1051_9, ~mu1051_4 -# 1051| mu1051_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_9 -#-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~mu1051_4 -# 1051| r1051_15(glval) = PointerAdd[1] : r1051_11, r0_6 -# 1051| r1051_16(char) = Load : &:r1051_15, ~mu1051_4 -# 1051| mu1051_17(char) = Store : &:r1051_8, r1051_16 -# 1051| r1051_18(glval) = VariableAddress[#return] : -# 1051| v1051_19(void) = ReturnValue : &:r1051_18, ~mu1051_4 -# 1051| v1051_20(void) = UnmodeledUse : mu* -# 1051| v1051_21(void) = AliasedUse : ~mu1051_4 -# 1051| v1051_22(void) = ExitFunction : +# 1051| v1051_1(void) = EnterFunction : +# 1051| mu1051_2(unknown) = AliasedDefinition : +# 1051| mu1051_3(unknown) = InitializeNonLocal : +# 1051| r1051_4(glval) = VariableAddress[#this] : +# 1051| mu1051_5(glval) = InitializeParameter[#this] : &:r1051_4 +# 1051| r1051_6(glval) = Load : &:r1051_4, ~m? +# 1051| mu1051_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1051_6 +# 1051| r1051_8(glval) = VariableAddress[f] : +# 1051| mu1051_9(float) = InitializeParameter[f] : &:r1051_8 +# 1051| r1051_10(glval) = VariableAddress[#return] : +# 1051| r1051_11(glval) = VariableAddress[#this] : +# 1051| r1051_12(lambda [] type at line 1051, col. 32 *) = Load : &:r1051_11, ~m? +# 1051| r1051_13(glval) = FieldAddress[s] : r1051_12 +# 1051| r1051_14(String &) = Load : &:r1051_13, ~m? +# 1051| r1051_15(glval) = CopyValue : r1051_14 +# 1051| r1051_16(glval) = FunctionAddress[c_str] : +# 1051| r1051_17(char *) = Call : func:r1051_16, this:r1051_15 +# 1051| mu1051_18(unknown) = ^CallSideEffect : ~m? +# 1051| v1051_19(void) = ^BufferReadSideEffect[-1] : &:r1051_15, ~m? +# 1051| mu1051_20(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_15 +# 1051| r1051_21(glval) = VariableAddress[#this] : +# 1051| r1051_22(lambda [] type at line 1051, col. 32 *) = Load : &:r1051_21, ~m? +# 1051| r1051_23(glval) = FieldAddress[x] : r1051_22 +# 1051| r1051_24(int) = Load : &:r1051_23, ~m? +# 1051| r1051_25(glval) = PointerAdd[1] : r1051_17, r1051_24 +# 1051| r1051_26(char) = Load : &:r1051_25, ~m? +# 1051| mu1051_27(char) = Store : &:r1051_10, r1051_26 +# 1051| v1051_28(void) = ReturnIndirection[#this] : &:r1051_6, ~m? +# 1051| r1051_29(glval) = VariableAddress[#return] : +# 1051| v1051_30(void) = ReturnValue : &:r1051_29, ~m? +# 1051| v1051_31(void) = AliasedUse : ~m? +# 1051| v1051_32(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 -# 1054| v1054_1(void) = EnterFunction : -# 1054| mu1054_2(unknown) = AliasedDefinition : -# 1054| mu1054_3(unknown) = InitializeNonLocal : -# 1054| mu1054_4(unknown) = UnmodeledDefinition : -# 1054| r1054_5(glval) = InitializeThis : -# 1054| r1054_6(glval) = VariableAddress[f] : -# 1054| mu1054_7(float) = InitializeParameter[f] : &:r1054_6 -# 1054| r1054_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1054_4 -# 1054| r1054_9(glval) = CopyValue : r0_3 -# 1054| r1054_10(glval) = FunctionAddress[c_str] : -# 1054| r1054_11(char *) = Call : func:r1054_10, this:r1054_9 -# 1054| mu1054_12(unknown) = ^CallSideEffect : ~mu1054_4 -# 1054| v1054_13(void) = ^BufferReadSideEffect[-1] : &:r1054_9, ~mu1054_4 -# 1054| mu1054_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_9 -#-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~mu1054_4 -#-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -# 1054| r1054_15(glval) = FieldAddress[i] : r0_7 -# 1054| r1054_16(int) = Load : &:r1054_15, ~mu1054_4 -# 1054| r1054_17(int) = Add : r0_6, r1054_16 -#-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -# 1054| r1054_18(glval) = FieldAddress[j] : r0_8 -# 1054| r1054_19(int &) = Load : &:r1054_18, ~mu1054_4 -# 1054| r1054_20(int) = Load : &:r1054_19, ~mu1054_4 -# 1054| r1054_21(int) = Sub : r1054_17, r1054_20 -# 1054| r1054_22(glval) = PointerAdd[1] : r1054_11, r1054_21 -# 1054| r1054_23(char) = Load : &:r1054_22, ~mu1054_4 -# 1054| mu1054_24(char) = Store : &:r1054_8, r1054_23 -# 1054| r1054_25(glval) = VariableAddress[#return] : -# 1054| v1054_26(void) = ReturnValue : &:r1054_25, ~mu1054_4 -# 1054| v1054_27(void) = UnmodeledUse : mu* -# 1054| v1054_28(void) = AliasedUse : ~mu1054_4 -# 1054| v1054_29(void) = ExitFunction : +# 1054| v1054_1(void) = EnterFunction : +# 1054| mu1054_2(unknown) = AliasedDefinition : +# 1054| mu1054_3(unknown) = InitializeNonLocal : +# 1054| r1054_4(glval) = VariableAddress[#this] : +# 1054| mu1054_5(glval) = InitializeParameter[#this] : &:r1054_4 +# 1054| r1054_6(glval) = Load : &:r1054_4, ~m? +# 1054| mu1054_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1054_6 +# 1054| r1054_8(glval) = VariableAddress[f] : +# 1054| mu1054_9(float) = InitializeParameter[f] : &:r1054_8 +# 1054| r1054_10(glval) = VariableAddress[#return] : +# 1054| r1054_11(glval) = VariableAddress[#this] : +# 1054| r1054_12(lambda [] type at line 1054, col. 23 *) = Load : &:r1054_11, ~m? +# 1054| r1054_13(glval) = FieldAddress[s] : r1054_12 +# 1054| r1054_14(String &) = Load : &:r1054_13, ~m? +# 1054| r1054_15(glval) = CopyValue : r1054_14 +# 1054| r1054_16(glval) = FunctionAddress[c_str] : +# 1054| r1054_17(char *) = Call : func:r1054_16, this:r1054_15 +# 1054| mu1054_18(unknown) = ^CallSideEffect : ~m? +# 1054| v1054_19(void) = ^BufferReadSideEffect[-1] : &:r1054_15, ~m? +# 1054| mu1054_20(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_15 +# 1054| r1054_21(glval) = VariableAddress[#this] : +# 1054| r1054_22(lambda [] type at line 1054, col. 23 *) = Load : &:r1054_21, ~m? +# 1054| r1054_23(glval) = FieldAddress[x] : r1054_22 +# 1054| r1054_24(int) = Load : &:r1054_23, ~m? +# 1054| r1054_25(glval) = VariableAddress[#this] : +# 1054| r1054_26(lambda [] type at line 1054, col. 23 *) = Load : &:r1054_25, ~m? +# 1054| r1054_27(glval) = FieldAddress[i] : r1054_26 +# 1054| r1054_28(int) = Load : &:r1054_27, ~m? +# 1054| r1054_29(int) = Add : r1054_24, r1054_28 +# 1054| r1054_30(glval) = VariableAddress[#this] : +# 1054| r1054_31(lambda [] type at line 1054, col. 23 *) = Load : &:r1054_30, ~m? +# 1054| r1054_32(glval) = FieldAddress[j] : r1054_31 +# 1054| r1054_33(int &) = Load : &:r1054_32, ~m? +# 1054| r1054_34(int) = Load : &:r1054_33, ~m? +# 1054| r1054_35(int) = Sub : r1054_29, r1054_34 +# 1054| r1054_36(glval) = PointerAdd[1] : r1054_17, r1054_35 +# 1054| r1054_37(char) = Load : &:r1054_36, ~m? +# 1054| mu1054_38(char) = Store : &:r1054_10, r1054_37 +# 1054| v1054_39(void) = ReturnIndirection[#this] : &:r1054_6, ~m? +# 1054| r1054_40(glval) = VariableAddress[#return] : +# 1054| v1054_41(void) = ReturnValue : &:r1054_40, ~m? +# 1054| v1054_42(void) = AliasedUse : ~m? +# 1054| v1054_43(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 -# 1077| v1077_1(void) = EnterFunction : -# 1077| mu1077_2(unknown) = AliasedDefinition : -# 1077| mu1077_3(unknown) = InitializeNonLocal : -# 1077| mu1077_4(unknown) = UnmodeledDefinition : -# 1077| r1077_5(glval &>) = VariableAddress[v] : -# 1077| mu1077_6(vector &) = InitializeParameter[v] : &:r1077_5 -# 1077| r1077_7(vector &) = Load : &:r1077_5, ~mu1077_4 -# 1077| mu1077_8(unknown) = InitializeIndirection[v] : &:r1077_7 -# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : -# 1078| r1078_2(glval &>) = VariableAddress[v] : -# 1078| r1078_3(vector &) = Load : &:r1078_2, ~mu1077_4 -# 1078| r1078_4(glval>) = CopyValue : r1078_3 -# 1078| r1078_5(vector &) = CopyValue : r1078_4 -# 1078| mu1078_6(vector &) = Store : &:r1078_1, r1078_5 -# 1078| r1078_7(glval) = VariableAddress[(__begin)] : -#-----| r0_1(glval &>) = VariableAddress[(__range)] : -#-----| r0_2(vector &) = Load : &:r0_1, ~mu1077_4 -#-----| r0_3(glval>) = CopyValue : r0_2 -# 1078| r1078_8(glval) = FunctionAddress[begin] : -# 1078| r1078_9(iterator) = Call : func:r1078_8, this:r0_3 -# 1078| mu1078_10(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~mu1077_4 -#-----| mu0_5(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 1078| mu1078_11(iterator) = Store : &:r1078_7, r1078_9 -# 1078| r1078_12(glval) = VariableAddress[(__end)] : -#-----| r0_6(glval &>) = VariableAddress[(__range)] : -#-----| r0_7(vector &) = Load : &:r0_6, ~mu1077_4 -#-----| r0_8(glval>) = CopyValue : r0_7 -# 1078| r1078_13(glval) = FunctionAddress[end] : -# 1078| r1078_14(iterator) = Call : func:r1078_13, this:r0_8 -# 1078| mu1078_15(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu1077_4 -#-----| mu0_10(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 -# 1078| mu1078_16(iterator) = Store : &:r1078_12, r1078_14 +# 1077| v1077_1(void) = EnterFunction : +# 1077| mu1077_2(unknown) = AliasedDefinition : +# 1077| mu1077_3(unknown) = InitializeNonLocal : +# 1077| r1077_4(glval &>) = VariableAddress[v] : +# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 +# 1077| r1077_6(vector &) = Load : &:r1077_4, ~m? +# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 +# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_2(glval &>) = VariableAddress[v] : +# 1078| r1078_3(vector &) = Load : &:r1078_2, ~m? +# 1078| r1078_4(glval>) = CopyValue : r1078_3 +# 1078| r1078_5(vector &) = CopyValue : r1078_4 +# 1078| mu1078_6(vector &) = Store : &:r1078_1, r1078_5 +# 1078| r1078_7(glval) = VariableAddress[(__begin)] : +# 1078| r1078_8(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_9(vector &) = Load : &:r1078_8, ~m? +#-----| r0_1(glval>) = CopyValue : r1078_9 +# 1078| r1078_10(glval) = FunctionAddress[begin] : +# 1078| r1078_11(iterator) = Call : func:r1078_10, this:r0_1 +# 1078| mu1078_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? +#-----| mu0_3(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 +# 1078| mu1078_13(iterator) = Store : &:r1078_7, r1078_11 +# 1078| r1078_14(glval) = VariableAddress[(__end)] : +# 1078| r1078_15(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_16(vector &) = Load : &:r1078_15, ~m? +#-----| r0_4(glval>) = CopyValue : r1078_16 +# 1078| r1078_17(glval) = FunctionAddress[end] : +# 1078| r1078_18(iterator) = Call : func:r1078_17, this:r0_4 +# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_5(void) = ^BufferReadSideEffect[-1] : &:r0_4, ~m? +#-----| mu0_6(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 +# 1078| mu1078_20(iterator) = Store : &:r1078_14, r1078_18 #-----| Goto -> Block 6 -#-----| Block 1 -#-----| r0_11(glval) = VariableAddress[(__begin)] : -#-----| r0_12(glval) = Convert : r0_11 -# 1084| r1084_1(glval) = FunctionAddress[operator!=] : -#-----| r0_13(glval) = VariableAddress[(__end)] : -#-----| r0_14(iterator) = Load : &:r0_13, ~mu1077_4 -# 1084| r1084_2(bool) = Call : func:r1084_1, this:r0_12, 0:r0_14 -# 1084| mu1084_3(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~mu1077_4 -#-----| mu0_16(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_12 -# 1084| v1084_4(void) = ConditionalBranch : r1084_2 +# 1084| Block 1 +# 1084| r1084_1(glval) = VariableAddress[(__begin)] : +#-----| r0_7(glval) = Convert : r1084_1 +# 1084| r1084_2(glval) = FunctionAddress[operator!=] : +# 1084| r1084_3(glval) = VariableAddress[(__end)] : +# 1084| r1084_4(iterator) = Load : &:r1084_3, ~m? +# 1084| r1084_5(bool) = Call : func:r1084_2, this:r0_7, 0:r1084_4 +# 1084| mu1084_6(unknown) = ^CallSideEffect : ~m? +#-----| v0_8(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? +#-----| mu0_9(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +# 1084| v1084_7(void) = ConditionalBranch : r1084_5 #-----| False -> Block 5 #-----| True -> Block 3 -#-----| Block 2 -#-----| r0_17(glval) = VariableAddress[(__begin)] : -# 1084| r1084_5(glval) = FunctionAddress[operator++] : -# 1084| r1084_6(iterator &) = Call : func:r1084_5, this:r0_17 -# 1084| mu1084_7(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_18(void) = ^BufferReadSideEffect[-1] : &:r0_17, ~mu1077_4 -#-----| mu0_19(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_17 -# 1084| r1084_8(glval) = CopyValue : r1084_6 +# 1084| Block 2 +# 1084| r1084_8(glval) = VariableAddress[(__begin)] : +# 1084| r1084_9(glval) = FunctionAddress[operator++] : +# 1084| r1084_10(iterator &) = Call : func:r1084_9, this:r1084_8 +# 1084| mu1084_11(unknown) = ^CallSideEffect : ~m? +# 1084| v1084_12(void) = ^BufferReadSideEffect[-1] : &:r1084_8, ~m? +# 1084| mu1084_13(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1084_8 +# 1084| r1084_14(glval) = CopyValue : r1084_10 #-----| Goto (back edge) -> Block 1 # 1084| Block 3 -# 1084| r1084_9(glval) = VariableAddress[e] : -#-----| r0_20(glval) = VariableAddress[(__begin)] : -#-----| r0_21(glval) = Convert : r0_20 -# 1084| r1084_10(glval) = FunctionAddress[operator*] : -# 1084| r1084_11(int &) = Call : func:r1084_10, this:r0_21 -# 1084| mu1084_12(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_22(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu1077_4 -#-----| mu0_23(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -# 1084| r1084_13(glval) = CopyValue : r1084_11 -# 1084| r1084_14(glval) = Convert : r1084_13 -# 1084| r1084_15(int &) = CopyValue : r1084_14 -# 1084| mu1084_16(int &) = Store : &:r1084_9, r1084_15 -# 1085| r1085_1(glval) = VariableAddress[e] : -# 1085| r1085_2(int &) = Load : &:r1085_1, ~mu1077_4 -# 1085| r1085_3(int) = Load : &:r1085_2, ~mu1077_4 -# 1085| r1085_4(int) = Constant[5] : -# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 -# 1085| v1085_6(void) = ConditionalBranch : r1085_5 +# 1084| r1084_15(glval) = VariableAddress[e] : +# 1084| r1084_16(glval) = VariableAddress[(__begin)] : +#-----| r0_10(glval) = Convert : r1084_16 +# 1084| r1084_17(glval) = FunctionAddress[operator*] : +# 1084| r1084_18(int &) = Call : func:r1084_17, this:r0_10 +# 1084| mu1084_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_11(void) = ^BufferReadSideEffect[-1] : &:r0_10, ~m? +#-----| mu0_12(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 +# 1084| r1084_20(glval) = CopyValue : r1084_18 +# 1084| r1084_21(glval) = Convert : r1084_20 +# 1084| r1084_22(int &) = CopyValue : r1084_21 +# 1084| mu1084_23(int &) = Store : &:r1084_15, r1084_22 +# 1085| r1085_1(glval) = VariableAddress[e] : +# 1085| r1085_2(int &) = Load : &:r1085_1, ~m? +# 1085| r1085_3(int) = Load : &:r1085_2, ~m? +# 1085| r1085_4(int) = Constant[5] : +# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 +# 1085| v1085_6(void) = ConditionalBranch : r1085_5 #-----| False -> Block 2 #-----| True -> Block 4 @@ -6302,42 +6213,41 @@ ir.cpp: # 1088| Block 5 # 1088| v1088_1(void) = NoOp : # 1089| v1089_1(void) = NoOp : -# 1077| v1077_9(void) = ReturnIndirection[v] : &:r1077_7, ~mu1077_4 -# 1077| v1077_10(void) = ReturnVoid : -# 1077| v1077_11(void) = UnmodeledUse : mu* -# 1077| v1077_12(void) = AliasedUse : ~mu1077_4 -# 1077| v1077_13(void) = ExitFunction : +# 1077| v1077_8(void) = ReturnIndirection[v] : &:r1077_6, ~m? +# 1077| v1077_9(void) = ReturnVoid : +# 1077| v1077_10(void) = AliasedUse : ~m? +# 1077| v1077_11(void) = ExitFunction : -#-----| Block 6 -#-----| r0_24(glval) = VariableAddress[(__begin)] : -#-----| r0_25(glval) = Convert : r0_24 -# 1078| r1078_17(glval) = FunctionAddress[operator!=] : -#-----| r0_26(glval) = VariableAddress[(__end)] : -#-----| r0_27(iterator) = Load : &:r0_26, ~mu1077_4 -# 1078| r1078_18(bool) = Call : func:r1078_17, this:r0_25, 0:r0_27 -# 1078| mu1078_19(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_28(void) = ^BufferReadSideEffect[-1] : &:r0_25, ~mu1077_4 -#-----| mu0_29(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 -# 1078| v1078_20(void) = ConditionalBranch : r1078_18 +# 1078| Block 6 +# 1078| r1078_21(glval) = VariableAddress[(__begin)] : +#-----| r0_13(glval) = Convert : r1078_21 +# 1078| r1078_22(glval) = FunctionAddress[operator!=] : +# 1078| r1078_23(glval) = VariableAddress[(__end)] : +# 1078| r1078_24(iterator) = Load : &:r1078_23, ~m? +# 1078| r1078_25(bool) = Call : func:r1078_22, this:r0_13, 0:r1078_24 +# 1078| mu1078_26(unknown) = ^CallSideEffect : ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_13, ~m? +#-----| mu0_15(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_13 +# 1078| v1078_27(void) = ConditionalBranch : r1078_25 #-----| False -> Block 10 #-----| True -> Block 7 # 1078| Block 7 -# 1078| r1078_21(glval) = VariableAddress[e] : -#-----| r0_30(glval) = VariableAddress[(__begin)] : -#-----| r0_31(glval) = Convert : r0_30 -# 1078| r1078_22(glval) = FunctionAddress[operator*] : -# 1078| r1078_23(int &) = Call : func:r1078_22, this:r0_31 -# 1078| mu1078_24(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_32(void) = ^BufferReadSideEffect[-1] : &:r0_31, ~mu1077_4 -#-----| mu0_33(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_31 -# 1078| r1078_25(int) = Load : &:r1078_23, ~mu1077_4 -# 1078| mu1078_26(int) = Store : &:r1078_21, r1078_25 -# 1079| r1079_1(glval) = VariableAddress[e] : -# 1079| r1079_2(int) = Load : &:r1079_1, ~mu1077_4 -# 1079| r1079_3(int) = Constant[0] : -# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 -# 1079| v1079_5(void) = ConditionalBranch : r1079_4 +# 1078| r1078_28(glval) = VariableAddress[e] : +# 1078| r1078_29(glval) = VariableAddress[(__begin)] : +#-----| r0_16(glval) = Convert : r1078_29 +# 1078| r1078_30(glval) = FunctionAddress[operator*] : +# 1078| r1078_31(int &) = Call : func:r1078_30, this:r0_16 +# 1078| mu1078_32(unknown) = ^CallSideEffect : ~m? +#-----| v0_17(void) = ^BufferReadSideEffect[-1] : &:r0_16, ~m? +#-----| mu0_18(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_16 +# 1078| r1078_33(int) = Load : &:r1078_31, ~m? +# 1078| mu1078_34(int) = Store : &:r1078_28, r1078_33 +# 1079| r1079_1(glval) = VariableAddress[e] : +# 1079| r1079_2(int) = Load : &:r1079_1, ~m? +# 1079| r1079_3(int) = Constant[0] : +# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 +# 1079| v1079_5(void) = ConditionalBranch : r1079_4 #-----| False -> Block 9 #-----| True -> Block 8 @@ -6346,43 +6256,43 @@ ir.cpp: #-----| Goto -> Block 9 # 1078| Block 9 -# 1078| v1078_27(void) = NoOp : -#-----| r0_34(glval) = VariableAddress[(__begin)] : -# 1078| r1078_28(glval) = FunctionAddress[operator++] : -# 1078| r1078_29(iterator &) = Call : func:r1078_28, this:r0_34 -# 1078| mu1078_30(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_35(void) = ^BufferReadSideEffect[-1] : &:r0_34, ~mu1077_4 -#-----| mu0_36(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 -# 1078| r1078_31(glval) = CopyValue : r1078_29 +# 1078| v1078_35(void) = NoOp : +# 1078| r1078_36(glval) = VariableAddress[(__begin)] : +# 1078| r1078_37(glval) = FunctionAddress[operator++] : +# 1078| r1078_38(iterator &) = Call : func:r1078_37, this:r1078_36 +# 1078| mu1078_39(unknown) = ^CallSideEffect : ~m? +# 1078| v1078_40(void) = ^BufferReadSideEffect[-1] : &:r1078_36, ~m? +# 1078| mu1078_41(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1078_36 +# 1078| r1078_42(glval) = CopyValue : r1078_38 #-----| Goto (back edge) -> Block 6 # 1084| Block 10 -# 1084| r1084_17(glval &>) = VariableAddress[(__range)] : -# 1084| r1084_18(glval &>) = VariableAddress[v] : -# 1084| r1084_19(vector &) = Load : &:r1084_18, ~mu1077_4 -# 1084| r1084_20(glval>) = CopyValue : r1084_19 -# 1084| r1084_21(vector &) = CopyValue : r1084_20 -# 1084| mu1084_22(vector &) = Store : &:r1084_17, r1084_21 -# 1084| r1084_23(glval) = VariableAddress[(__begin)] : -#-----| r0_37(glval &>) = VariableAddress[(__range)] : -#-----| r0_38(vector &) = Load : &:r0_37, ~mu1077_4 -#-----| r0_39(glval>) = CopyValue : r0_38 -# 1084| r1084_24(glval) = FunctionAddress[begin] : -# 1084| r1084_25(iterator) = Call : func:r1084_24, this:r0_39 -# 1084| mu1084_26(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_40(void) = ^BufferReadSideEffect[-1] : &:r0_39, ~mu1077_4 -#-----| mu0_41(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_39 -# 1084| mu1084_27(iterator) = Store : &:r1084_23, r1084_25 -# 1084| r1084_28(glval) = VariableAddress[(__end)] : -#-----| r0_42(glval &>) = VariableAddress[(__range)] : -#-----| r0_43(vector &) = Load : &:r0_42, ~mu1077_4 -#-----| r0_44(glval>) = CopyValue : r0_43 -# 1084| r1084_29(glval) = FunctionAddress[end] : -# 1084| r1084_30(iterator) = Call : func:r1084_29, this:r0_44 -# 1084| mu1084_31(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_45(void) = ^BufferReadSideEffect[-1] : &:r0_44, ~mu1077_4 -#-----| mu0_46(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_44 -# 1084| mu1084_32(iterator) = Store : &:r1084_28, r1084_30 +# 1084| r1084_24(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_25(glval &>) = VariableAddress[v] : +# 1084| r1084_26(vector &) = Load : &:r1084_25, ~m? +# 1084| r1084_27(glval>) = CopyValue : r1084_26 +# 1084| r1084_28(vector &) = CopyValue : r1084_27 +# 1084| mu1084_29(vector &) = Store : &:r1084_24, r1084_28 +# 1084| r1084_30(glval) = VariableAddress[(__begin)] : +# 1084| r1084_31(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_32(vector &) = Load : &:r1084_31, ~m? +#-----| r0_19(glval>) = CopyValue : r1084_32 +# 1084| r1084_33(glval) = FunctionAddress[begin] : +# 1084| r1084_34(iterator) = Call : func:r1084_33, this:r0_19 +# 1084| mu1084_35(unknown) = ^CallSideEffect : ~m? +#-----| v0_20(void) = ^BufferReadSideEffect[-1] : &:r0_19, ~m? +#-----| mu0_21(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 +# 1084| mu1084_36(iterator) = Store : &:r1084_30, r1084_34 +# 1084| r1084_37(glval) = VariableAddress[(__end)] : +# 1084| r1084_38(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_39(vector &) = Load : &:r1084_38, ~m? +#-----| r0_22(glval>) = CopyValue : r1084_39 +# 1084| r1084_40(glval) = FunctionAddress[end] : +# 1084| r1084_41(iterator) = Call : func:r1084_40, this:r0_22 +# 1084| mu1084_42(unknown) = ^CallSideEffect : ~m? +#-----| v0_23(void) = ^BufferReadSideEffect[-1] : &:r0_22, ~m? +#-----| mu0_24(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 +# 1084| mu1084_43(iterator) = Store : &:r1084_37, r1084_41 #-----| Goto -> Block 1 # 1108| int AsmStmt(int) @@ -6390,88 +6300,81 @@ ir.cpp: # 1108| v1108_1(void) = EnterFunction : # 1108| mu1108_2(unknown) = AliasedDefinition : # 1108| mu1108_3(unknown) = InitializeNonLocal : -# 1108| mu1108_4(unknown) = UnmodeledDefinition : -# 1108| r1108_5(glval) = VariableAddress[x] : -# 1108| mu1108_6(int) = InitializeParameter[x] : &:r1108_5 -# 1109| mu1109_1(unknown) = InlineAsm : ~mu1108_4 +# 1108| r1108_4(glval) = VariableAddress[x] : +# 1108| mu1108_5(int) = InitializeParameter[x] : &:r1108_4 +# 1109| mu1109_1(unknown) = InlineAsm : ~m? # 1110| r1110_1(glval) = VariableAddress[#return] : # 1110| r1110_2(glval) = VariableAddress[x] : -# 1110| r1110_3(int) = Load : &:r1110_2, ~mu1108_4 +# 1110| r1110_3(int) = Load : &:r1110_2, ~m? # 1110| mu1110_4(int) = Store : &:r1110_1, r1110_3 -# 1108| r1108_7(glval) = VariableAddress[#return] : -# 1108| v1108_8(void) = ReturnValue : &:r1108_7, ~mu1108_4 -# 1108| v1108_9(void) = UnmodeledUse : mu* -# 1108| v1108_10(void) = AliasedUse : ~mu1108_4 -# 1108| v1108_11(void) = ExitFunction : +# 1108| r1108_6(glval) = VariableAddress[#return] : +# 1108| v1108_7(void) = ReturnValue : &:r1108_6, ~m? +# 1108| v1108_8(void) = AliasedUse : ~m? +# 1108| v1108_9(void) = ExitFunction : # 1113| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) # 1113| Block 0 # 1113| v1113_1(void) = EnterFunction : # 1113| mu1113_2(unknown) = AliasedDefinition : # 1113| mu1113_3(unknown) = InitializeNonLocal : -# 1113| mu1113_4(unknown) = UnmodeledDefinition : -# 1113| r1113_5(glval) = VariableAddress[a] : -# 1113| mu1113_6(unsigned int &) = InitializeParameter[a] : &:r1113_5 -# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~mu1113_4 -# 1113| mu1113_8(unknown) = InitializeIndirection[a] : &:r1113_7 -# 1113| r1113_9(glval) = VariableAddress[b] : -# 1113| mu1113_10(unsigned int) = InitializeParameter[b] : &:r1113_9 -# 1113| r1113_11(glval) = VariableAddress[c] : -# 1113| mu1113_12(unsigned int &) = InitializeParameter[c] : &:r1113_11 -# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_4 -# 1113| mu1113_14(unknown) = InitializeIndirection[c] : &:r1113_13 -# 1113| r1113_15(glval) = VariableAddress[d] : -# 1113| mu1113_16(unsigned int) = InitializeParameter[d] : &:r1113_15 +# 1113| r1113_4(glval) = VariableAddress[a] : +# 1113| mu1113_5(unsigned int &) = InitializeParameter[a] : &:r1113_4 +# 1113| r1113_6(unsigned int &) = Load : &:r1113_4, ~m? +# 1113| mu1113_7(unknown) = InitializeIndirection[a] : &:r1113_6 +# 1113| r1113_8(glval) = VariableAddress[b] : +# 1113| mu1113_9(unsigned int) = InitializeParameter[b] : &:r1113_8 +# 1113| r1113_10(glval) = VariableAddress[c] : +# 1113| mu1113_11(unsigned int &) = InitializeParameter[c] : &:r1113_10 +# 1113| r1113_12(unsigned int &) = Load : &:r1113_10, ~m? +# 1113| mu1113_13(unknown) = InitializeIndirection[c] : &:r1113_12 +# 1113| r1113_14(glval) = VariableAddress[d] : +# 1113| mu1113_15(unsigned int) = InitializeParameter[d] : &:r1113_14 # 1118| r1118_1(glval) = VariableAddress[a] : -# 1118| r1118_2(unsigned int &) = Load : &:r1118_1, ~mu1113_4 +# 1118| r1118_2(unsigned int &) = Load : &:r1118_1, ~m? # 1118| r1118_3(glval) = CopyValue : r1118_2 # 1118| r1118_4(glval) = VariableAddress[b] : # 1118| r1118_5(glval) = VariableAddress[c] : -# 1118| r1118_6(unsigned int &) = Load : &:r1118_5, ~mu1113_4 -# 1118| r1118_7(unsigned int) = Load : &:r1118_6, ~mu1113_4 +# 1118| r1118_6(unsigned int &) = Load : &:r1118_5, ~m? +# 1118| r1118_7(unsigned int) = Load : &:r1118_6, ~m? # 1118| r1118_8(glval) = VariableAddress[d] : -# 1118| r1118_9(unsigned int) = Load : &:r1118_8, ~mu1113_4 -# 1115| mu1115_1(unknown) = InlineAsm : ~mu1113_4, 0:r1118_3, 1:r1118_4, 2:r1118_7, 3:r1118_9 +# 1118| r1118_9(unsigned int) = Load : &:r1118_8, ~m? +# 1115| mu1115_1(unknown) = InlineAsm : ~m?, 0:r1118_3, 1:r1118_4, 2:r1118_7, 3:r1118_9 # 1120| v1120_1(void) = NoOp : -# 1113| v1113_17(void) = ReturnIndirection[a] : &:r1113_7, ~mu1113_4 -# 1113| v1113_18(void) = ReturnIndirection[c] : &:r1113_13, ~mu1113_4 -# 1113| v1113_19(void) = ReturnVoid : -# 1113| v1113_20(void) = UnmodeledUse : mu* -# 1113| v1113_21(void) = AliasedUse : ~mu1113_4 -# 1113| v1113_22(void) = ExitFunction : +# 1113| v1113_16(void) = ReturnIndirection[a] : &:r1113_6, ~m? +# 1113| v1113_17(void) = ReturnIndirection[c] : &:r1113_12, ~m? +# 1113| v1113_18(void) = ReturnVoid : +# 1113| v1113_19(void) = AliasedUse : ~m? +# 1113| v1113_20(void) = ExitFunction : # 1122| void ExternDeclarations() # 1122| Block 0 -# 1122| v1122_1(void) = EnterFunction : -# 1122| mu1122_2(unknown) = AliasedDefinition : -# 1122| mu1122_3(unknown) = InitializeNonLocal : -# 1122| mu1122_4(unknown) = UnmodeledDefinition : -# 1125| r1125_1(glval) = VariableAddress[x] : -# 1125| mu1125_2(int) = Uninitialized[x] : &:r1125_1 -# 1126| r1126_1(glval) = VariableAddress[y] : -# 1126| mu1126_2(int) = Uninitialized[y] : &:r1126_1 -# 1127| r1127_1(glval) = VariableAddress[h] : -# 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 -# 1129| v1129_1(void) = NoOp : -# 1122| v1122_5(void) = ReturnVoid : -# 1122| v1122_6(void) = UnmodeledUse : mu* -# 1122| v1122_7(void) = AliasedUse : ~mu1122_4 -# 1122| v1122_8(void) = ExitFunction : +# 1122| v1122_1(void) = EnterFunction : +# 1122| mu1122_2(unknown) = AliasedDefinition : +# 1122| mu1122_3(unknown) = InitializeNonLocal : +# 1125| r1125_1(glval) = VariableAddress[x] : +# 1125| mu1125_2(int) = Uninitialized[x] : &:r1125_1 +# 1126| r1126_1(glval) = VariableAddress[y] : +# 1126| mu1126_2(int) = Uninitialized[y] : &:r1126_1 +# 1127| r1127_1(glval) = VariableAddress[h] : +# 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 +# 1129| v1129_1(void) = NoOp : +# 1122| v1122_4(void) = ReturnVoid : +# 1122| v1122_5(void) = AliasedUse : ~m? +# 1122| v1122_6(void) = ExitFunction : # 1137| void ExternDeclarationsInMacro() # 1137| Block 0 -# 1137| v1137_1(void) = EnterFunction : -# 1137| mu1137_2(unknown) = AliasedDefinition : -# 1137| mu1137_3(unknown) = InitializeNonLocal : -# 1137| mu1137_4(unknown) = UnmodeledDefinition : -# 1139| r1139_1(glval) = VariableAddress[i] : -# 1139| r1139_2(int) = Constant[0] : -# 1139| mu1139_3(int) = Store : &:r1139_1, r1139_2 +# 1137| v1137_1(void) = EnterFunction : +# 1137| mu1137_2(unknown) = AliasedDefinition : +# 1137| mu1137_3(unknown) = InitializeNonLocal : +# 1139| r1139_1(glval) = VariableAddress[i] : +# 1139| r1139_2(int) = Constant[0] : +# 1139| mu1139_3(int) = Store : &:r1139_1, r1139_2 #-----| Goto -> Block 1 # 1139| Block 1 # 1139| r1139_4(glval) = VariableAddress[i] : -# 1139| r1139_5(int) = Load : &:r1139_4, ~mu1137_4 +# 1139| r1139_5(int) = Load : &:r1139_4, ~m? # 1139| r1139_6(int) = Constant[10] : # 1139| r1139_7(bool) = CompareLT : r1139_5, r1139_6 # 1139| v1139_8(void) = ConditionalBranch : r1139_7 @@ -6480,7 +6383,7 @@ ir.cpp: # 1139| Block 2 # 1139| r1139_9(glval) = VariableAddress[i] : -# 1139| r1139_10(int) = Load : &:r1139_9, ~mu1137_4 +# 1139| r1139_10(int) = Load : &:r1139_9, ~m? # 1139| r1139_11(int) = Constant[1] : # 1139| r1139_12(int) = Add : r1139_10, r1139_11 # 1139| mu1139_13(int) = Store : &:r1139_9, r1139_12 @@ -6489,35 +6392,32 @@ ir.cpp: # 1139| Block 3 # 1139| v1139_14(void) = NoOp : # 1140| v1140_1(void) = NoOp : -# 1137| v1137_5(void) = ReturnVoid : -# 1137| v1137_6(void) = UnmodeledUse : mu* -# 1137| v1137_7(void) = AliasedUse : ~mu1137_4 -# 1137| v1137_8(void) = ExitFunction : +# 1137| v1137_4(void) = ReturnVoid : +# 1137| v1137_5(void) = AliasedUse : ~m? +# 1137| v1137_6(void) = ExitFunction : # 1142| void TryCatchNoCatchAny(bool) # 1142| Block 0 # 1142| v1142_1(void) = EnterFunction : # 1142| mu1142_2(unknown) = AliasedDefinition : # 1142| mu1142_3(unknown) = InitializeNonLocal : -# 1142| mu1142_4(unknown) = UnmodeledDefinition : -# 1142| r1142_5(glval) = VariableAddress[b] : -# 1142| mu1142_6(bool) = InitializeParameter[b] : &:r1142_5 +# 1142| r1142_4(glval) = VariableAddress[b] : +# 1142| mu1142_5(bool) = InitializeParameter[b] : &:r1142_4 # 1144| r1144_1(glval) = VariableAddress[x] : # 1144| r1144_2(int) = Constant[5] : # 1144| mu1144_3(int) = Store : &:r1144_1, r1144_2 # 1145| r1145_1(glval) = VariableAddress[b] : -# 1145| r1145_2(bool) = Load : &:r1145_1, ~mu1142_4 +# 1145| r1145_2(bool) = Load : &:r1145_1, ~m? # 1145| v1145_3(void) = ConditionalBranch : r1145_2 #-----| False -> Block 4 #-----| True -> Block 3 # 1142| Block 1 -# 1142| v1142_7(void) = UnmodeledUse : mu* -# 1142| v1142_8(void) = AliasedUse : ~mu1142_4 -# 1142| v1142_9(void) = ExitFunction : +# 1142| v1142_6(void) = AliasedUse : ~m? +# 1142| v1142_7(void) = ExitFunction : # 1142| Block 2 -# 1142| v1142_10(void) = Unwind : +# 1142| v1142_8(void) = Unwind : #-----| Goto -> Block 1 # 1146| Block 3 @@ -6525,12 +6425,12 @@ ir.cpp: # 1146| r1146_2(glval) = StringConstant["string literal"] : # 1146| r1146_3(char *) = Convert : r1146_2 # 1146| mu1146_4(char *) = Store : &:r1146_1, r1146_3 -# 1146| v1146_5(void) = ThrowValue : &:r1146_1, ~mu1142_4 +# 1146| v1146_5(void) = ThrowValue : &:r1146_1, ~m? #-----| Exception -> Block 9 # 1148| Block 4 # 1148| r1148_1(glval) = VariableAddress[x] : -# 1148| r1148_2(int) = Load : &:r1148_1, ~mu1142_4 +# 1148| r1148_2(int) = Load : &:r1148_1, ~m? # 1148| r1148_3(int) = Constant[2] : # 1148| r1148_4(bool) = CompareLT : r1148_2, r1148_3 # 1148| v1148_5(void) = ConditionalBranch : r1148_4 @@ -6539,7 +6439,7 @@ ir.cpp: # 1149| Block 5 # 1149| r1149_1(glval) = VariableAddress[b] : -# 1149| r1149_2(bool) = Load : &:r1149_1, ~mu1142_4 +# 1149| r1149_2(bool) = Load : &:r1149_1, ~m? # 1149| v1149_3(void) = ConditionalBranch : r1149_2 #-----| False -> Block 7 #-----| True -> Block 6 @@ -6549,7 +6449,7 @@ ir.cpp: # 1149| r1149_5(glval) = VariableAddress[#temp1149:11] : # 1149| mu1149_6(int) = Store : &:r1149_5, r1149_4 # 1149| r1149_7(glval) = VariableAddress[#temp1149:11] : -# 1149| r1149_8(int) = Load : &:r1149_7, ~mu1142_4 +# 1149| r1149_8(int) = Load : &:r1149_7, ~m? # 1149| r1149_9(glval) = VariableAddress[x] : # 1149| mu1149_10(int) = Store : &:r1149_9, r1149_8 #-----| Goto -> Block 8 @@ -6561,11 +6461,11 @@ ir.cpp: # 1149| r1149_14(glval) = StringConstant["String object"] : # 1149| r1149_15(char *) = Convert : r1149_14 # 1149| v1149_16(void) = Call : func:r1149_13, this:r1149_11, 0:r1149_15 -# 1149| mu1149_17(unknown) = ^CallSideEffect : ~mu1142_4 +# 1149| mu1149_17(unknown) = ^CallSideEffect : ~m? # 1149| mu1149_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1149_11 -# 1149| v1149_19(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~mu1142_4 +# 1149| v1149_19(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~m? # 1149| mu1149_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r1149_15 -# 1149| v1149_21(void) = ThrowValue : &:r1149_11, ~mu1142_4 +# 1149| v1149_21(void) = ThrowValue : &:r1149_11, ~m? #-----| Exception -> Block 9 # 1151| Block 8 @@ -6582,19 +6482,19 @@ ir.cpp: # 1153| Block 10 # 1153| r1153_2(glval) = VariableAddress[s] : # 1153| mu1153_3(char *) = InitializeParameter[s] : &:r1153_2 -# 1153| r1153_4(char *) = Load : &:r1153_2, ~mu1142_4 +# 1153| r1153_4(char *) = Load : &:r1153_2, ~m? # 1153| mu1153_5(unknown) = InitializeIndirection[s] : &:r1153_4 # 1154| r1154_1(glval) = VariableAddress[#throw1154:5] : # 1154| mu1154_2(String) = Uninitialized[#throw1154:5] : &:r1154_1 # 1154| r1154_3(glval) = FunctionAddress[String] : # 1154| r1154_4(glval) = VariableAddress[s] : -# 1154| r1154_5(char *) = Load : &:r1154_4, ~mu1142_4 +# 1154| r1154_5(char *) = Load : &:r1154_4, ~m? # 1154| v1154_6(void) = Call : func:r1154_3, this:r1154_1, 0:r1154_5 -# 1154| mu1154_7(unknown) = ^CallSideEffect : ~mu1142_4 +# 1154| mu1154_7(unknown) = ^CallSideEffect : ~m? # 1154| mu1154_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1154_1 -# 1154| v1154_9(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~mu1142_4 +# 1154| v1154_9(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~m? # 1154| mu1154_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1154_5 -# 1154| v1154_11(void) = ThrowValue : &:r1154_1, ~mu1142_4 +# 1154| v1154_11(void) = ThrowValue : &:r1154_1, ~m? #-----| Exception -> Block 2 # 1156| Block 11 @@ -6605,14 +6505,14 @@ ir.cpp: # 1156| Block 12 # 1156| r1156_2(glval) = VariableAddress[e] : # 1156| mu1156_3(String &) = InitializeParameter[e] : &:r1156_2 -# 1156| r1156_4(String &) = Load : &:r1156_2, ~mu1142_4 +# 1156| r1156_4(String &) = Load : &:r1156_2, ~m? # 1156| mu1156_5(unknown) = InitializeIndirection[e] : &:r1156_4 # 1156| v1156_6(void) = NoOp : #-----| Goto -> Block 13 # 1158| Block 13 -# 1158| v1158_1(void) = NoOp : -# 1142| v1142_11(void) = ReturnVoid : +# 1158| v1158_1(void) = NoOp : +# 1142| v1142_9(void) = ReturnVoid : #-----| Goto -> Block 1 # 1162| void VectorTypes(int) @@ -6620,9 +6520,8 @@ ir.cpp: # 1162| v1162_1(void) = EnterFunction : # 1162| mu1162_2(unknown) = AliasedDefinition : # 1162| mu1162_3(unknown) = InitializeNonLocal : -# 1162| mu1162_4(unknown) = UnmodeledDefinition : -# 1162| r1162_5(glval) = VariableAddress[i] : -# 1162| mu1162_6(int) = InitializeParameter[i] : &:r1162_5 +# 1162| r1162_4(glval) = VariableAddress[i] : +# 1162| mu1162_5(int) = InitializeParameter[i] : &:r1162_4 # 1163| r1163_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1163| mu1163_2(__attribute((vector_size(16UL))) int) = Uninitialized[vi4] : &:r1163_1 # 1163| r1163_3(int) = Constant[0] : @@ -6644,49 +6543,47 @@ ir.cpp: # 1164| r1164_1(glval) = VariableAddress[x] : # 1164| r1164_2(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1164| r1164_3(glval) = VariableAddress[i] : -# 1164| r1164_4(int) = Load : &:r1164_3, ~mu1162_4 +# 1164| r1164_4(int) = Load : &:r1164_3, ~m? # 1164| r1164_5(glval) = PointerAdd[4] : r1164_2, r1164_4 -# 1164| r1164_6(int) = Load : &:r1164_5, ~mu1162_4 +# 1164| r1164_6(int) = Load : &:r1164_5, ~m? # 1164| mu1164_7(int) = Store : &:r1164_1, r1164_6 # 1165| r1165_1(glval) = VariableAddress[x] : -# 1165| r1165_2(int) = Load : &:r1165_1, ~mu1162_4 +# 1165| r1165_2(int) = Load : &:r1165_1, ~m? # 1165| r1165_3(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1165| r1165_4(glval) = VariableAddress[i] : -# 1165| r1165_5(int) = Load : &:r1165_4, ~mu1162_4 +# 1165| r1165_5(int) = Load : &:r1165_4, ~m? # 1165| r1165_6(glval) = PointerAdd[4] : r1165_3, r1165_5 # 1165| mu1165_7(int) = Store : &:r1165_6, r1165_2 # 1166| r1166_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : # 1166| r1166_2(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1166| r1166_3(__attribute((vector_size(16UL))) int) = Load : &:r1166_2, ~mu1162_4 +# 1166| r1166_3(__attribute((vector_size(16UL))) int) = Load : &:r1166_2, ~m? # 1166| r1166_4(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1166| r1166_5(__attribute((vector_size(16UL))) int) = Load : &:r1166_4, ~mu1162_4 -#-----| r0_1(int) = Constant[3] : -# 1166| r1166_6(int) = Constant[2] : -# 1166| r1166_7(int) = Constant[1] : -# 1166| r1166_8(int) = Constant[0] : -# 1166| r1166_9(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r1166_3, 1:r1166_5, 2:r0_1, 3:r1166_6, 4:r1166_7, 5:r1166_8 -# 1166| mu1166_10(__attribute((vector_size(16UL))) int) = Store : &:r1166_1, r1166_9 +# 1166| r1166_5(__attribute((vector_size(16UL))) int) = Load : &:r1166_4, ~m? +# 1166| r1166_6(int) = Constant[3] : +# 1166| r1166_7(int) = Constant[2] : +# 1166| r1166_8(int) = Constant[1] : +# 1166| r1166_9(int) = Constant[0] : +# 1166| r1166_10(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r1166_3, 1:r1166_5, 2:r1166_6, 3:r1166_7, 4:r1166_8, 5:r1166_9 +# 1166| mu1166_11(__attribute((vector_size(16UL))) int) = Store : &:r1166_1, r1166_10 # 1167| r1167_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1167| r1167_2(__attribute((vector_size(16UL))) int) = Load : &:r1167_1, ~mu1162_4 +# 1167| r1167_2(__attribute((vector_size(16UL))) int) = Load : &:r1167_1, ~m? # 1167| r1167_3(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : -# 1167| r1167_4(__attribute((vector_size(16UL))) int) = Load : &:r1167_3, ~mu1162_4 +# 1167| r1167_4(__attribute((vector_size(16UL))) int) = Load : &:r1167_3, ~m? # 1167| r1167_5(__attribute((vector_size(16UL))) int) = Add : r1167_2, r1167_4 # 1167| r1167_6(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1167| mu1167_7(__attribute((vector_size(16UL))) int) = Store : &:r1167_6, r1167_5 # 1168| v1168_1(void) = NoOp : -# 1162| v1162_7(void) = ReturnVoid : -# 1162| v1162_8(void) = UnmodeledUse : mu* -# 1162| v1162_9(void) = AliasedUse : ~mu1162_4 -# 1162| v1162_10(void) = ExitFunction : +# 1162| v1162_6(void) = ReturnVoid : +# 1162| v1162_7(void) = AliasedUse : ~m? +# 1162| v1162_8(void) = ExitFunction : # 1172| int ModeledCallTarget(int) # 1172| Block 0 # 1172| v1172_1(void) = EnterFunction : # 1172| mu1172_2(unknown) = AliasedDefinition : # 1172| mu1172_3(unknown) = InitializeNonLocal : -# 1172| mu1172_4(unknown) = UnmodeledDefinition : -# 1172| r1172_5(glval) = VariableAddress[x] : -# 1172| mu1172_6(int) = InitializeParameter[x] : &:r1172_5 +# 1172| r1172_4(glval) = VariableAddress[x] : +# 1172| mu1172_5(int) = InitializeParameter[x] : &:r1172_4 # 1173| r1173_1(glval) = VariableAddress[y] : # 1173| mu1173_2(int) = Uninitialized[y] : &:r1173_1 # 1174| r1174_1(glval) = FunctionAddress[memcpy] : @@ -6698,53 +6595,49 @@ ir.cpp: # 1174| r1174_7(void *) = Convert : r1174_6 # 1174| r1174_8(int) = Constant[4] : # 1174| r1174_9(void *) = Call : func:r1174_1, 0:r1174_4, 1:r1174_7, 2:r1174_8 -# 1174| v1174_10(void) = ^SizedBufferReadSideEffect[1] : &:r1174_7, r1174_8, ~mu1172_4 +# 1174| v1174_10(void) = ^SizedBufferReadSideEffect[1] : &:r1174_7, r1174_8, ~m? # 1174| mu1174_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r1174_4, r1174_8 # 1175| r1175_1(glval) = VariableAddress[#return] : # 1175| r1175_2(glval) = VariableAddress[y] : -# 1175| r1175_3(int) = Load : &:r1175_2, ~mu1172_4 +# 1175| r1175_3(int) = Load : &:r1175_2, ~m? # 1175| mu1175_4(int) = Store : &:r1175_1, r1175_3 -# 1172| r1172_7(glval) = VariableAddress[#return] : -# 1172| v1172_8(void) = ReturnValue : &:r1172_7, ~mu1172_4 -# 1172| v1172_9(void) = UnmodeledUse : mu* -# 1172| v1172_10(void) = AliasedUse : ~mu1172_4 -# 1172| v1172_11(void) = ExitFunction : +# 1172| r1172_6(glval) = VariableAddress[#return] : +# 1172| v1172_7(void) = ReturnValue : &:r1172_6, ~m? +# 1172| v1172_8(void) = AliasedUse : ~m? +# 1172| v1172_9(void) = ExitFunction : # 1178| String ReturnObjectImpl() # 1178| Block 0 # 1178| v1178_1(void) = EnterFunction : # 1178| mu1178_2(unknown) = AliasedDefinition : # 1178| mu1178_3(unknown) = InitializeNonLocal : -# 1178| mu1178_4(unknown) = UnmodeledDefinition : # 1179| r1179_1(glval) = VariableAddress[#return] : # 1179| mu1179_2(String) = Uninitialized[#return] : &:r1179_1 # 1179| r1179_3(glval) = FunctionAddress[String] : # 1179| r1179_4(glval) = StringConstant["foo"] : # 1179| r1179_5(char *) = Convert : r1179_4 # 1179| r1179_6(String) = Call : func:r1179_3, this:r1179_1, 0:r1179_5 -# 1179| mu1179_7(unknown) = ^CallSideEffect : ~mu1178_4 +# 1179| mu1179_7(unknown) = ^CallSideEffect : ~m? # 1179| mu1179_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1179_1 -# 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~mu1178_4 +# 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~m? # 1179| mu1179_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1179_5 -# 1178| r1178_5(glval) = VariableAddress[#return] : -# 1178| v1178_6(void) = ReturnValue : &:r1178_5, ~mu1178_4 -# 1178| v1178_7(void) = UnmodeledUse : mu* -# 1178| v1178_8(void) = AliasedUse : ~mu1178_4 -# 1178| v1178_9(void) = ExitFunction : +# 1178| r1178_4(glval) = VariableAddress[#return] : +# 1178| v1178_5(void) = ReturnValue : &:r1178_4, ~m? +# 1178| v1178_6(void) = AliasedUse : ~m? +# 1178| v1178_7(void) = ExitFunction : # 1182| void switch1Case(int) # 1182| Block 0 # 1182| v1182_1(void) = EnterFunction : # 1182| mu1182_2(unknown) = AliasedDefinition : # 1182| mu1182_3(unknown) = InitializeNonLocal : -# 1182| mu1182_4(unknown) = UnmodeledDefinition : -# 1182| r1182_5(glval) = VariableAddress[x] : -# 1182| mu1182_6(int) = InitializeParameter[x] : &:r1182_5 +# 1182| r1182_4(glval) = VariableAddress[x] : +# 1182| mu1182_5(int) = InitializeParameter[x] : &:r1182_4 # 1183| r1183_1(glval) = VariableAddress[y] : # 1183| r1183_2(int) = Constant[0] : # 1183| mu1183_3(int) = Store : &:r1183_1, r1183_2 # 1184| r1184_1(glval) = VariableAddress[x] : -# 1184| r1184_2(int) = Load : &:r1184_1, ~mu1182_4 +# 1184| r1184_2(int) = Load : &:r1184_1, ~m? # 1184| v1184_3(void) = Switch : r1184_2 #-----| Case[1] -> Block 1 #-----| Default -> Block 2 @@ -6759,27 +6652,25 @@ ir.cpp: # 1188| Block 2 # 1188| r1188_1(glval) = VariableAddress[z] : # 1188| r1188_2(glval) = VariableAddress[y] : -# 1188| r1188_3(int) = Load : &:r1188_2, ~mu1182_4 +# 1188| r1188_3(int) = Load : &:r1188_2, ~m? # 1188| mu1188_4(int) = Store : &:r1188_1, r1188_3 # 1189| v1189_1(void) = NoOp : -# 1182| v1182_7(void) = ReturnVoid : -# 1182| v1182_8(void) = UnmodeledUse : mu* -# 1182| v1182_9(void) = AliasedUse : ~mu1182_4 -# 1182| v1182_10(void) = ExitFunction : +# 1182| v1182_6(void) = ReturnVoid : +# 1182| v1182_7(void) = AliasedUse : ~m? +# 1182| v1182_8(void) = ExitFunction : # 1191| void switch2Case_fallthrough(int) # 1191| Block 0 # 1191| v1191_1(void) = EnterFunction : # 1191| mu1191_2(unknown) = AliasedDefinition : # 1191| mu1191_3(unknown) = InitializeNonLocal : -# 1191| mu1191_4(unknown) = UnmodeledDefinition : -# 1191| r1191_5(glval) = VariableAddress[x] : -# 1191| mu1191_6(int) = InitializeParameter[x] : &:r1191_5 +# 1191| r1191_4(glval) = VariableAddress[x] : +# 1191| mu1191_5(int) = InitializeParameter[x] : &:r1191_4 # 1192| r1192_1(glval) = VariableAddress[y] : # 1192| r1192_2(int) = Constant[0] : # 1192| mu1192_3(int) = Store : &:r1192_1, r1192_2 # 1193| r1193_1(glval) = VariableAddress[x] : -# 1193| r1193_2(int) = Load : &:r1193_1, ~mu1191_4 +# 1193| r1193_2(int) = Load : &:r1193_1, ~m? # 1193| v1193_3(void) = Switch : r1193_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6802,27 +6693,25 @@ ir.cpp: # 1199| Block 3 # 1199| r1199_1(glval) = VariableAddress[z] : # 1199| r1199_2(glval) = VariableAddress[y] : -# 1199| r1199_3(int) = Load : &:r1199_2, ~mu1191_4 +# 1199| r1199_3(int) = Load : &:r1199_2, ~m? # 1199| mu1199_4(int) = Store : &:r1199_1, r1199_3 # 1200| v1200_1(void) = NoOp : -# 1191| v1191_7(void) = ReturnVoid : -# 1191| v1191_8(void) = UnmodeledUse : mu* -# 1191| v1191_9(void) = AliasedUse : ~mu1191_4 -# 1191| v1191_10(void) = ExitFunction : +# 1191| v1191_6(void) = ReturnVoid : +# 1191| v1191_7(void) = AliasedUse : ~m? +# 1191| v1191_8(void) = ExitFunction : # 1202| void switch2Case(int) # 1202| Block 0 # 1202| v1202_1(void) = EnterFunction : # 1202| mu1202_2(unknown) = AliasedDefinition : # 1202| mu1202_3(unknown) = InitializeNonLocal : -# 1202| mu1202_4(unknown) = UnmodeledDefinition : -# 1202| r1202_5(glval) = VariableAddress[x] : -# 1202| mu1202_6(int) = InitializeParameter[x] : &:r1202_5 +# 1202| r1202_4(glval) = VariableAddress[x] : +# 1202| mu1202_5(int) = InitializeParameter[x] : &:r1202_4 # 1203| r1203_1(glval) = VariableAddress[y] : # 1203| r1203_2(int) = Constant[0] : # 1203| mu1203_3(int) = Store : &:r1203_1, r1203_2 # 1204| r1204_1(glval) = VariableAddress[x] : -# 1204| r1204_2(int) = Load : &:r1204_1, ~mu1202_4 +# 1204| r1204_2(int) = Load : &:r1204_1, ~m? # 1204| v1204_3(void) = Switch : r1204_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6847,27 +6736,25 @@ ir.cpp: # 1210| v1210_1(void) = NoOp : # 1211| r1211_1(glval) = VariableAddress[z] : # 1211| r1211_2(glval) = VariableAddress[y] : -# 1211| r1211_3(int) = Load : &:r1211_2, ~mu1202_4 +# 1211| r1211_3(int) = Load : &:r1211_2, ~m? # 1211| mu1211_4(int) = Store : &:r1211_1, r1211_3 # 1212| v1212_1(void) = NoOp : -# 1202| v1202_7(void) = ReturnVoid : -# 1202| v1202_8(void) = UnmodeledUse : mu* -# 1202| v1202_9(void) = AliasedUse : ~mu1202_4 -# 1202| v1202_10(void) = ExitFunction : +# 1202| v1202_6(void) = ReturnVoid : +# 1202| v1202_7(void) = AliasedUse : ~m? +# 1202| v1202_8(void) = ExitFunction : # 1214| void switch2Case_default(int) # 1214| Block 0 # 1214| v1214_1(void) = EnterFunction : # 1214| mu1214_2(unknown) = AliasedDefinition : # 1214| mu1214_3(unknown) = InitializeNonLocal : -# 1214| mu1214_4(unknown) = UnmodeledDefinition : -# 1214| r1214_5(glval) = VariableAddress[x] : -# 1214| mu1214_6(int) = InitializeParameter[x] : &:r1214_5 +# 1214| r1214_4(glval) = VariableAddress[x] : +# 1214| mu1214_5(int) = InitializeParameter[x] : &:r1214_4 # 1215| r1215_1(glval) = VariableAddress[y] : # 1215| r1215_2(int) = Constant[0] : # 1215| mu1215_3(int) = Store : &:r1215_1, r1215_2 # 1216| r1216_1(glval) = VariableAddress[x] : -# 1216| r1216_2(int) = Load : &:r1216_1, ~mu1214_4 +# 1216| r1216_2(int) = Load : &:r1216_1, ~m? # 1216| v1216_3(void) = Switch : r1216_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6900,24 +6787,22 @@ ir.cpp: # 1227| v1227_1(void) = NoOp : # 1228| r1228_1(glval) = VariableAddress[z] : # 1228| r1228_2(glval) = VariableAddress[y] : -# 1228| r1228_3(int) = Load : &:r1228_2, ~mu1214_4 +# 1228| r1228_3(int) = Load : &:r1228_2, ~m? # 1228| mu1228_4(int) = Store : &:r1228_1, r1228_3 # 1229| v1229_1(void) = NoOp : -# 1214| v1214_7(void) = ReturnVoid : -# 1214| v1214_8(void) = UnmodeledUse : mu* -# 1214| v1214_9(void) = AliasedUse : ~mu1214_4 -# 1214| v1214_10(void) = ExitFunction : +# 1214| v1214_6(void) = ReturnVoid : +# 1214| v1214_7(void) = AliasedUse : ~m? +# 1214| v1214_8(void) = ExitFunction : # 1231| int staticLocalInit(int) # 1231| Block 0 # 1231| v1231_1(void) = EnterFunction : # 1231| mu1231_2(unknown) = AliasedDefinition : # 1231| mu1231_3(unknown) = InitializeNonLocal : -# 1231| mu1231_4(unknown) = UnmodeledDefinition : -# 1231| r1231_5(glval) = VariableAddress[x] : -# 1231| mu1231_6(int) = InitializeParameter[x] : &:r1231_5 +# 1231| r1231_4(glval) = VariableAddress[x] : +# 1231| mu1231_5(int) = InitializeParameter[x] : &:r1231_4 # 1234| r1234_1(glval) = VariableAddress[c#init] : -# 1234| r1234_2(bool) = Load : &:r1234_1, ~mu1231_4 +# 1234| r1234_2(bool) = Load : &:r1234_1, ~m? # 1234| v1234_3(void) = ConditionalBranch : r1234_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -6925,27 +6810,26 @@ ir.cpp: # 1237| Block 1 # 1237| r1237_1(glval) = VariableAddress[#return] : # 1237| r1237_2(glval) = VariableAddress[a] : -# 1237| r1237_3(int) = Load : &:r1237_2, ~mu1231_4 +# 1237| r1237_3(int) = Load : &:r1237_2, ~m? # 1237| r1237_4(glval) = VariableAddress[b] : -# 1237| r1237_5(int) = Load : &:r1237_4, ~mu1231_4 +# 1237| r1237_5(int) = Load : &:r1237_4, ~m? # 1237| r1237_6(int) = Add : r1237_3, r1237_5 # 1237| r1237_7(glval) = VariableAddress[c] : -# 1237| r1237_8(int) = Load : &:r1237_7, ~mu1231_4 +# 1237| r1237_8(int) = Load : &:r1237_7, ~m? # 1237| r1237_9(int) = Add : r1237_6, r1237_8 # 1237| r1237_10(glval) = VariableAddress[d] : -# 1237| r1237_11(int) = Load : &:r1237_10, ~mu1231_4 +# 1237| r1237_11(int) = Load : &:r1237_10, ~m? # 1237| r1237_12(int) = Add : r1237_9, r1237_11 # 1237| mu1237_13(int) = Store : &:r1237_1, r1237_12 -# 1231| r1231_7(glval) = VariableAddress[#return] : -# 1231| v1231_8(void) = ReturnValue : &:r1231_7, ~mu1231_4 -# 1231| v1231_9(void) = UnmodeledUse : mu* -# 1231| v1231_10(void) = AliasedUse : ~mu1231_4 -# 1231| v1231_11(void) = ExitFunction : +# 1231| r1231_6(glval) = VariableAddress[#return] : +# 1231| v1231_7(void) = ReturnValue : &:r1231_6, ~m? +# 1231| v1231_8(void) = AliasedUse : ~m? +# 1231| v1231_9(void) = ExitFunction : # 1234| Block 2 # 1234| r1234_4(glval) = VariableAddress[c] : # 1234| r1234_5(glval) = VariableAddress[x] : -# 1234| r1234_6(int) = Load : &:r1234_5, ~mu1231_4 +# 1234| r1234_6(int) = Load : &:r1234_5, ~m? # 1234| mu1234_7(int) = Store : &:r1234_4, r1234_6 # 1234| r1234_8(bool) = Constant[1] : # 1234| mu1234_9(bool) = Store : &:r1234_1, r1234_8 @@ -6956,20 +6840,19 @@ ir.cpp: # 1240| v1240_1(void) = EnterFunction : # 1240| mu1240_2(unknown) = AliasedDefinition : # 1240| mu1240_3(unknown) = InitializeNonLocal : -# 1240| mu1240_4(unknown) = UnmodeledDefinition : -# 1240| r1240_5(glval) = VariableAddress[dynamic] : -# 1240| mu1240_6(char *) = InitializeParameter[dynamic] : &:r1240_5 -# 1240| r1240_7(char *) = Load : &:r1240_5, ~mu1240_4 -# 1240| mu1240_8(unknown) = InitializeIndirection[dynamic] : &:r1240_7 +# 1240| r1240_4(glval) = VariableAddress[dynamic] : +# 1240| mu1240_5(char *) = InitializeParameter[dynamic] : &:r1240_4 +# 1240| r1240_6(char *) = Load : &:r1240_4, ~m? +# 1240| mu1240_7(unknown) = InitializeIndirection[dynamic] : &:r1240_6 # 1241| r1241_1(glval) = VariableAddress[a#init] : -# 1241| r1241_2(bool) = Load : &:r1241_1, ~mu1240_4 +# 1241| r1241_2(bool) = Load : &:r1241_1, ~m? # 1241| v1241_3(void) = ConditionalBranch : r1241_2 #-----| False -> Block 6 #-----| True -> Block 1 # 1242| Block 1 # 1242| r1242_1(glval) = VariableAddress[b#init] : -# 1242| r1242_2(bool) = Load : &:r1242_1, ~mu1240_4 +# 1242| r1242_2(bool) = Load : &:r1242_1, ~m? # 1242| v1242_3(void) = ConditionalBranch : r1242_2 #-----| False -> Block 2 #-----| True -> Block 3 @@ -6980,9 +6863,9 @@ ir.cpp: # 1242| r1242_6(glval) = StringConstant["static"] : # 1242| r1242_7(char *) = Convert : r1242_6 # 1242| v1242_8(void) = Call : func:r1242_5, this:r1242_4, 0:r1242_7 -# 1242| mu1242_9(unknown) = ^CallSideEffect : ~mu1240_4 +# 1242| mu1242_9(unknown) = ^CallSideEffect : ~m? # 1242| mu1242_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1242_4 -# 1242| v1242_11(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~mu1240_4 +# 1242| v1242_11(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~m? # 1242| mu1242_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1242_7 # 1242| r1242_13(bool) = Constant[1] : # 1242| mu1242_14(bool) = Store : &:r1242_1, r1242_13 @@ -6990,7 +6873,7 @@ ir.cpp: # 1243| Block 3 # 1243| r1243_1(glval) = VariableAddress[c#init] : -# 1243| r1243_2(bool) = Load : &:r1243_1, ~mu1240_4 +# 1243| r1243_2(bool) = Load : &:r1243_1, ~m? # 1243| v1243_3(void) = ConditionalBranch : r1243_2 #-----| False -> Block 4 #-----| True -> Block 5 @@ -6999,11 +6882,11 @@ ir.cpp: # 1243| r1243_4(glval) = VariableAddress[c] : # 1243| r1243_5(glval) = FunctionAddress[String] : # 1243| r1243_6(glval) = VariableAddress[dynamic] : -# 1243| r1243_7(char *) = Load : &:r1243_6, ~mu1240_4 +# 1243| r1243_7(char *) = Load : &:r1243_6, ~m? # 1243| v1243_8(void) = Call : func:r1243_5, this:r1243_4, 0:r1243_7 -# 1243| mu1243_9(unknown) = ^CallSideEffect : ~mu1240_4 +# 1243| mu1243_9(unknown) = ^CallSideEffect : ~m? # 1243| mu1243_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1243_4 -# 1243| v1243_11(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~mu1240_4 +# 1243| v1243_11(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~m? # 1243| mu1243_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1243_7 # 1243| r1243_13(bool) = Constant[1] : # 1243| mu1243_14(bool) = Store : &:r1243_1, r1243_13 @@ -7011,17 +6894,16 @@ ir.cpp: # 1244| Block 5 # 1244| v1244_1(void) = NoOp : -# 1240| v1240_9(void) = ReturnIndirection[dynamic] : &:r1240_7, ~mu1240_4 -# 1240| v1240_10(void) = ReturnVoid : -# 1240| v1240_11(void) = UnmodeledUse : mu* -# 1240| v1240_12(void) = AliasedUse : ~mu1240_4 -# 1240| v1240_13(void) = ExitFunction : +# 1240| v1240_8(void) = ReturnIndirection[dynamic] : &:r1240_6, ~m? +# 1240| v1240_9(void) = ReturnVoid : +# 1240| v1240_10(void) = AliasedUse : ~m? +# 1240| v1240_11(void) = ExitFunction : # 1241| Block 6 # 1241| r1241_4(glval) = VariableAddress[a] : #-----| r0_1(glval) = FunctionAddress[String] : #-----| v0_2(void) = Call : func:r0_1, this:r1241_4 -#-----| mu0_3(unknown) = ^CallSideEffect : ~mu1240_4 +#-----| mu0_3(unknown) = ^CallSideEffect : ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r1241_4 # 1241| r1241_5(bool) = Constant[1] : # 1241| mu1241_6(bool) = Store : &:r1241_1, r1241_5 @@ -7032,15 +6914,14 @@ ir.cpp: # 1251| v1251_1(void) = EnterFunction : # 1251| mu1251_2(unknown) = AliasedDefinition : # 1251| mu1251_3(unknown) = InitializeNonLocal : -# 1251| mu1251_4(unknown) = UnmodeledDefinition : -# 1251| r1251_5(glval) = VariableAddress[s1] : -# 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5 -# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_4 -# 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7 -# 1251| r1251_9(glval) = VariableAddress[s2] : -# 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9 -# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_4 -# 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11 +# 1251| r1251_4(glval) = VariableAddress[s1] : +# 1251| mu1251_5(char *) = InitializeParameter[s1] : &:r1251_4 +# 1251| r1251_6(char *) = Load : &:r1251_4, ~m? +# 1251| mu1251_7(unknown) = InitializeIndirection[s1] : &:r1251_6 +# 1251| r1251_8(glval) = VariableAddress[s2] : +# 1251| mu1251_9(char *) = InitializeParameter[s2] : &:r1251_8 +# 1251| r1251_10(char *) = Load : &:r1251_8, ~m? +# 1251| mu1251_11(unknown) = InitializeIndirection[s2] : &:r1251_10 # 1252| r1252_1(glval) = VariableAddress[buffer] : # 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1 # 1252| r1252_3(int) = Constant[0] : @@ -7055,81 +6936,77 @@ ir.cpp: # 1254| r1254_2(glval) = VariableAddress[buffer] : # 1254| r1254_3(char *) = Convert : r1254_2 # 1254| r1254_4(glval) = VariableAddress[s1] : -# 1254| r1254_5(char *) = Load : &:r1254_4, ~mu1251_4 +# 1254| r1254_5(char *) = Load : &:r1254_4, ~m? # 1254| r1254_6(char *) = Convert : r1254_5 # 1254| r1254_7(char *) = Call : func:r1254_1, 0:r1254_3, 1:r1254_6 -# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~mu1251_4 +# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~m? # 1254| mu1254_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1254_3 # 1255| r1255_1(glval) = FunctionAddress[strcat] : # 1255| r1255_2(glval) = VariableAddress[buffer] : # 1255| r1255_3(char *) = Convert : r1255_2 # 1255| r1255_4(glval) = VariableAddress[s2] : -# 1255| r1255_5(char *) = Load : &:r1255_4, ~mu1251_4 +# 1255| r1255_5(char *) = Load : &:r1255_4, ~m? # 1255| r1255_6(char *) = Convert : r1255_5 # 1255| r1255_7(char *) = Call : func:r1255_1, 0:r1255_3, 1:r1255_6 -# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~mu1251_4 -# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~mu1251_4 +# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~m? +# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~m? # 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3 # 1256| v1256_1(void) = NoOp : -# 1251| v1251_13(void) = ReturnIndirection[s1] : &:r1251_7, ~mu1251_4 -# 1251| v1251_14(void) = ReturnIndirection[s2] : &:r1251_11, ~mu1251_4 -# 1251| v1251_15(void) = ReturnVoid : -# 1251| v1251_16(void) = UnmodeledUse : mu* -# 1251| v1251_17(void) = AliasedUse : ~mu1251_4 -# 1251| v1251_18(void) = ExitFunction : +# 1251| v1251_12(void) = ReturnIndirection[s1] : &:r1251_6, ~m? +# 1251| v1251_13(void) = ReturnIndirection[s2] : &:r1251_10, ~m? +# 1251| v1251_14(void) = ReturnVoid : +# 1251| v1251_15(void) = AliasedUse : ~m? +# 1251| v1251_16(void) = ExitFunction : # 1261| void A::static_member(A*, int) # 1261| Block 0 # 1261| v1261_1(void) = EnterFunction : # 1261| mu1261_2(unknown) = AliasedDefinition : # 1261| mu1261_3(unknown) = InitializeNonLocal : -# 1261| mu1261_4(unknown) = UnmodeledDefinition : -# 1261| r1261_5(glval) = VariableAddress[a] : -# 1261| mu1261_6(A *) = InitializeParameter[a] : &:r1261_5 -# 1261| r1261_7(A *) = Load : &:r1261_5, ~mu1261_4 -# 1261| mu1261_8(unknown) = InitializeIndirection[a] : &:r1261_7 -# 1261| r1261_9(glval) = VariableAddress[x] : -# 1261| mu1261_10(int) = InitializeParameter[x] : &:r1261_9 +# 1261| r1261_4(glval) = VariableAddress[a] : +# 1261| mu1261_5(A *) = InitializeParameter[a] : &:r1261_4 +# 1261| r1261_6(A *) = Load : &:r1261_4, ~m? +# 1261| mu1261_7(unknown) = InitializeIndirection[a] : &:r1261_6 +# 1261| r1261_8(glval) = VariableAddress[x] : +# 1261| mu1261_9(int) = InitializeParameter[x] : &:r1261_8 # 1262| r1262_1(glval) = VariableAddress[x] : -# 1262| r1262_2(int) = Load : &:r1262_1, ~mu1261_4 +# 1262| r1262_2(int) = Load : &:r1262_1, ~m? # 1262| r1262_3(glval) = VariableAddress[a] : -# 1262| r1262_4(A *) = Load : &:r1262_3, ~mu1261_4 +# 1262| r1262_4(A *) = Load : &:r1262_3, ~m? # 1262| r1262_5(glval) = FieldAddress[member] : r1262_4 # 1262| mu1262_6(int) = Store : &:r1262_5, r1262_2 # 1263| v1263_1(void) = NoOp : -# 1261| v1261_11(void) = ReturnIndirection[a] : &:r1261_7, ~mu1261_4 -# 1261| v1261_12(void) = ReturnVoid : -# 1261| v1261_13(void) = UnmodeledUse : mu* -# 1261| v1261_14(void) = AliasedUse : ~mu1261_4 -# 1261| v1261_15(void) = ExitFunction : +# 1261| v1261_10(void) = ReturnIndirection[a] : &:r1261_6, ~m? +# 1261| v1261_11(void) = ReturnVoid : +# 1261| v1261_12(void) = AliasedUse : ~m? +# 1261| v1261_13(void) = ExitFunction : # 1270| void test_static_member_functions(int, A*) # 1270| Block 0 # 1270| v1270_1(void) = EnterFunction : # 1270| mu1270_2(unknown) = AliasedDefinition : # 1270| mu1270_3(unknown) = InitializeNonLocal : -# 1270| mu1270_4(unknown) = UnmodeledDefinition : -# 1270| r1270_5(glval) = VariableAddress[int_arg] : -# 1270| mu1270_6(int) = InitializeParameter[int_arg] : &:r1270_5 -# 1270| r1270_7(glval) = VariableAddress[a_arg] : -# 1270| mu1270_8(A *) = InitializeParameter[a_arg] : &:r1270_7 -# 1270| r1270_9(A *) = Load : &:r1270_7, ~mu1270_4 -# 1270| mu1270_10(unknown) = InitializeIndirection[a_arg] : &:r1270_9 +# 1270| r1270_4(glval) = VariableAddress[int_arg] : +# 1270| mu1270_5(int) = InitializeParameter[int_arg] : &:r1270_4 +# 1270| r1270_6(glval) = VariableAddress[a_arg] : +# 1270| mu1270_7(A *) = InitializeParameter[a_arg] : &:r1270_6 +# 1270| r1270_8(A *) = Load : &:r1270_6, ~m? +# 1270| mu1270_9(unknown) = InitializeIndirection[a_arg] : &:r1270_8 # 1271| r1271_1(glval) = VariableAddress[c] : # 1271| mu1271_2(C) = Uninitialized[c] : &:r1271_1 # 1271| r1271_3(glval) = FunctionAddress[C] : # 1271| v1271_4(void) = Call : func:r1271_3, this:r1271_1 -# 1271| mu1271_5(unknown) = ^CallSideEffect : ~mu1270_4 +# 1271| mu1271_5(unknown) = ^CallSideEffect : ~m? # 1271| mu1271_6(C) = ^IndirectMayWriteSideEffect[-1] : &:r1271_1 # 1272| r1272_1(glval) = VariableAddress[c] : # 1272| r1272_2(glval) = FunctionAddress[StaticMemberFunction] : # 1272| r1272_3(int) = Constant[10] : # 1272| r1272_4(int) = Call : func:r1272_2, 0:r1272_3 -# 1272| mu1272_5(unknown) = ^CallSideEffect : ~mu1270_4 +# 1272| mu1272_5(unknown) = ^CallSideEffect : ~m? # 1273| r1273_1(glval) = FunctionAddress[StaticMemberFunction] : # 1273| r1273_2(int) = Constant[10] : # 1273| r1273_3(int) = Call : func:r1273_1, 0:r1273_2 -# 1273| mu1273_4(unknown) = ^CallSideEffect : ~mu1270_4 +# 1273| mu1273_4(unknown) = ^CallSideEffect : ~m? # 1275| r1275_1(glval) = VariableAddress[a] : # 1275| mu1275_2(A) = Uninitialized[a] : &:r1275_1 # 1276| r1276_1(glval) = VariableAddress[a] : @@ -7137,86 +7014,84 @@ ir.cpp: # 1276| r1276_3(glval) = VariableAddress[a] : # 1276| r1276_4(A *) = CopyValue : r1276_3 # 1276| r1276_5(glval) = VariableAddress[int_arg] : -# 1276| r1276_6(int) = Load : &:r1276_5, ~mu1270_4 +# 1276| r1276_6(int) = Load : &:r1276_5, ~m? # 1276| v1276_7(void) = Call : func:r1276_2, 0:r1276_4, 1:r1276_6 -# 1276| mu1276_8(unknown) = ^CallSideEffect : ~mu1270_4 -# 1276| v1276_9(void) = ^BufferReadSideEffect[0] : &:r1276_4, ~mu1270_4 +# 1276| mu1276_8(unknown) = ^CallSideEffect : ~m? +# 1276| v1276_9(void) = ^BufferReadSideEffect[0] : &:r1276_4, ~m? # 1276| mu1276_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1276_4 # 1277| r1277_1(glval) = FunctionAddress[static_member] : # 1277| r1277_2(glval) = VariableAddress[a] : # 1277| r1277_3(A *) = CopyValue : r1277_2 # 1277| r1277_4(glval) = VariableAddress[int_arg] : -# 1277| r1277_5(int) = Load : &:r1277_4, ~mu1270_4 +# 1277| r1277_5(int) = Load : &:r1277_4, ~m? # 1277| v1277_6(void) = Call : func:r1277_1, 0:r1277_3, 1:r1277_5 -# 1277| mu1277_7(unknown) = ^CallSideEffect : ~mu1270_4 -# 1277| v1277_8(void) = ^BufferReadSideEffect[0] : &:r1277_3, ~mu1270_4 +# 1277| mu1277_7(unknown) = ^CallSideEffect : ~m? +# 1277| v1277_8(void) = ^BufferReadSideEffect[0] : &:r1277_3, ~m? # 1277| mu1277_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1277_3 # 1279| r1279_1(glval) = VariableAddress[a] : # 1279| r1279_2(A *) = CopyValue : r1279_1 # 1279| r1279_3(glval) = FunctionAddress[static_member] : # 1279| r1279_4(glval) = VariableAddress[a_arg] : -# 1279| r1279_5(A *) = Load : &:r1279_4, ~mu1270_4 +# 1279| r1279_5(A *) = Load : &:r1279_4, ~m? # 1279| r1279_6(glval) = VariableAddress[int_arg] : -# 1279| r1279_7(int) = Load : &:r1279_6, ~mu1270_4 +# 1279| r1279_7(int) = Load : &:r1279_6, ~m? # 1279| r1279_8(int) = Constant[2] : # 1279| r1279_9(int) = Add : r1279_7, r1279_8 # 1279| v1279_10(void) = Call : func:r1279_3, 0:r1279_5, 1:r1279_9 -# 1279| mu1279_11(unknown) = ^CallSideEffect : ~mu1270_4 -# 1279| v1279_12(void) = ^BufferReadSideEffect[0] : &:r1279_5, ~mu1270_4 +# 1279| mu1279_11(unknown) = ^CallSideEffect : ~m? +# 1279| v1279_12(void) = ^BufferReadSideEffect[0] : &:r1279_5, ~m? # 1279| mu1279_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r1279_5 # 1280| r1280_1(glval) = VariableAddress[a_arg] : -# 1280| r1280_2(A *) = Load : &:r1280_1, ~mu1270_4 +# 1280| r1280_2(A *) = Load : &:r1280_1, ~m? # 1280| r1280_3(glval) = CopyValue : r1280_2 # 1280| r1280_4(glval) = FunctionAddress[static_member] : # 1280| r1280_5(glval) = VariableAddress[a] : # 1280| r1280_6(A *) = CopyValue : r1280_5 # 1280| r1280_7(int) = Constant[99] : # 1280| v1280_8(void) = Call : func:r1280_4, 0:r1280_6, 1:r1280_7 -# 1280| mu1280_9(unknown) = ^CallSideEffect : ~mu1270_4 -# 1280| v1280_10(void) = ^BufferReadSideEffect[0] : &:r1280_6, ~mu1270_4 +# 1280| mu1280_9(unknown) = ^CallSideEffect : ~m? +# 1280| v1280_10(void) = ^BufferReadSideEffect[0] : &:r1280_6, ~m? # 1280| mu1280_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r1280_6 # 1281| r1281_1(glval) = VariableAddress[a_arg] : -# 1281| r1281_2(A *) = Load : &:r1281_1, ~mu1270_4 +# 1281| r1281_2(A *) = Load : &:r1281_1, ~m? # 1281| r1281_3(glval) = FunctionAddress[static_member] : # 1281| r1281_4(glval) = VariableAddress[a_arg] : -# 1281| r1281_5(A *) = Load : &:r1281_4, ~mu1270_4 +# 1281| r1281_5(A *) = Load : &:r1281_4, ~m? # 1281| r1281_6(int) = Constant[-1] : # 1281| v1281_7(void) = Call : func:r1281_3, 0:r1281_5, 1:r1281_6 -# 1281| mu1281_8(unknown) = ^CallSideEffect : ~mu1270_4 -# 1281| v1281_9(void) = ^BufferReadSideEffect[0] : &:r1281_5, ~mu1270_4 +# 1281| mu1281_8(unknown) = ^CallSideEffect : ~m? +# 1281| v1281_9(void) = ^BufferReadSideEffect[0] : &:r1281_5, ~m? # 1281| mu1281_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1281_5 # 1283| r1283_1(glval) = VariableAddress[a] : # 1283| r1283_2(glval) = FunctionAddress[static_member_without_def] : # 1283| v1283_3(void) = Call : func:r1283_2 -# 1283| mu1283_4(unknown) = ^CallSideEffect : ~mu1270_4 +# 1283| mu1283_4(unknown) = ^CallSideEffect : ~m? # 1284| r1284_1(glval) = FunctionAddress[static_member_without_def] : # 1284| v1284_2(void) = Call : func:r1284_1 -# 1284| mu1284_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1284| mu1284_3(unknown) = ^CallSideEffect : ~m? # 1286| r1286_1(glval) = FunctionAddress[getAnInstanceOfA] : # 1286| r1286_2(A *) = Call : func:r1286_1 -# 1286| mu1286_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| mu1286_3(unknown) = ^CallSideEffect : ~m? # 1286| r1286_4(glval) = FunctionAddress[static_member_without_def] : # 1286| v1286_5(void) = Call : func:r1286_4 -# 1286| mu1286_6(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| mu1286_6(unknown) = ^CallSideEffect : ~m? # 1287| v1287_1(void) = NoOp : -# 1270| v1270_11(void) = ReturnIndirection[a_arg] : &:r1270_9, ~mu1270_4 -# 1270| v1270_12(void) = ReturnVoid : -# 1270| v1270_13(void) = UnmodeledUse : mu* -# 1270| v1270_14(void) = AliasedUse : ~mu1270_4 -# 1270| v1270_15(void) = ExitFunction : +# 1270| v1270_10(void) = ReturnIndirection[a_arg] : &:r1270_8, ~m? +# 1270| v1270_11(void) = ReturnVoid : +# 1270| v1270_12(void) = AliasedUse : ~m? +# 1270| v1270_13(void) = ExitFunction : # 1289| int missingReturnValue(bool, int) # 1289| Block 0 # 1289| v1289_1(void) = EnterFunction : # 1289| mu1289_2(unknown) = AliasedDefinition : # 1289| mu1289_3(unknown) = InitializeNonLocal : -# 1289| mu1289_4(unknown) = UnmodeledDefinition : -# 1289| r1289_5(glval) = VariableAddress[b] : -# 1289| mu1289_6(bool) = InitializeParameter[b] : &:r1289_5 -# 1289| r1289_7(glval) = VariableAddress[x] : -# 1289| mu1289_8(int) = InitializeParameter[x] : &:r1289_7 +# 1289| r1289_4(glval) = VariableAddress[b] : +# 1289| mu1289_5(bool) = InitializeParameter[b] : &:r1289_4 +# 1289| r1289_6(glval) = VariableAddress[x] : +# 1289| mu1289_7(int) = InitializeParameter[x] : &:r1289_6 # 1290| r1290_1(glval) = VariableAddress[b] : -# 1290| r1290_2(bool) = Load : &:r1290_1, ~mu1289_4 +# 1290| r1290_2(bool) = Load : &:r1290_1, ~m? # 1290| v1290_3(void) = ConditionalBranch : r1290_2 #-----| False -> Block 1 #-----| True -> Block 2 @@ -7227,66 +7102,62 @@ ir.cpp: # 1291| Block 2 # 1291| r1291_1(glval) = VariableAddress[#return] : # 1291| r1291_2(glval) = VariableAddress[x] : -# 1291| r1291_3(int) = Load : &:r1291_2, ~mu1289_4 +# 1291| r1291_3(int) = Load : &:r1291_2, ~m? # 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 -# 1289| r1289_9(glval) = VariableAddress[#return] : -# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~mu1289_4 -# 1289| v1289_11(void) = UnmodeledUse : mu* -# 1289| v1289_12(void) = AliasedUse : ~mu1289_4 -# 1289| v1289_13(void) = ExitFunction : +# 1289| r1289_8(glval) = VariableAddress[#return] : +# 1289| v1289_9(void) = ReturnValue : &:r1289_8, ~m? +# 1289| v1289_10(void) = AliasedUse : ~m? +# 1289| v1289_11(void) = ExitFunction : # 1295| void returnVoid(int, int) # 1295| Block 0 # 1295| v1295_1(void) = EnterFunction : # 1295| mu1295_2(unknown) = AliasedDefinition : # 1295| mu1295_3(unknown) = InitializeNonLocal : -# 1295| mu1295_4(unknown) = UnmodeledDefinition : -# 1295| r1295_5(glval) = VariableAddress[x] : -# 1295| mu1295_6(int) = InitializeParameter[x] : &:r1295_5 -# 1295| r1295_7(glval) = VariableAddress[y] : -# 1295| mu1295_8(int) = InitializeParameter[y] : &:r1295_7 +# 1295| r1295_4(glval) = VariableAddress[x] : +# 1295| mu1295_5(int) = InitializeParameter[x] : &:r1295_4 +# 1295| r1295_6(glval) = VariableAddress[y] : +# 1295| mu1295_7(int) = InitializeParameter[y] : &:r1295_6 # 1296| r1296_1(glval) = FunctionAddress[IntegerOps] : # 1296| r1296_2(glval) = VariableAddress[x] : -# 1296| r1296_3(int) = Load : &:r1296_2, ~mu1295_4 +# 1296| r1296_3(int) = Load : &:r1296_2, ~m? # 1296| r1296_4(glval) = VariableAddress[y] : -# 1296| r1296_5(int) = Load : &:r1296_4, ~mu1295_4 +# 1296| r1296_5(int) = Load : &:r1296_4, ~m? # 1296| v1296_6(void) = Call : func:r1296_1, 0:r1296_3, 1:r1296_5 -# 1296| mu1296_7(unknown) = ^CallSideEffect : ~mu1295_4 +# 1296| mu1296_7(unknown) = ^CallSideEffect : ~m? # 1296| v1296_8(void) = NoOp : -# 1295| v1295_9(void) = ReturnVoid : -# 1295| v1295_10(void) = UnmodeledUse : mu* -# 1295| v1295_11(void) = AliasedUse : ~mu1295_4 -# 1295| v1295_12(void) = ExitFunction : +# 1295| v1295_8(void) = ReturnVoid : +# 1295| v1295_9(void) = AliasedUse : ~m? +# 1295| v1295_10(void) = ExitFunction : # 1299| void gccBinaryConditional(bool, int, long) # 1299| Block 0 # 1299| v1299_1(void) = EnterFunction : # 1299| mu1299_2(unknown) = AliasedDefinition : # 1299| mu1299_3(unknown) = InitializeNonLocal : -# 1299| mu1299_4(unknown) = UnmodeledDefinition : -# 1299| r1299_5(glval) = VariableAddress[b] : -# 1299| mu1299_6(bool) = InitializeParameter[b] : &:r1299_5 -# 1299| r1299_7(glval) = VariableAddress[x] : -# 1299| mu1299_8(int) = InitializeParameter[x] : &:r1299_7 -# 1299| r1299_9(glval) = VariableAddress[y] : -# 1299| mu1299_10(long) = InitializeParameter[y] : &:r1299_9 +# 1299| r1299_4(glval) = VariableAddress[b] : +# 1299| mu1299_5(bool) = InitializeParameter[b] : &:r1299_4 +# 1299| r1299_6(glval) = VariableAddress[x] : +# 1299| mu1299_7(int) = InitializeParameter[x] : &:r1299_6 +# 1299| r1299_8(glval) = VariableAddress[y] : +# 1299| mu1299_9(long) = InitializeParameter[y] : &:r1299_8 # 1300| r1300_1(glval) = VariableAddress[z] : # 1300| r1300_2(glval) = VariableAddress[x] : -# 1300| r1300_3(int) = Load : &:r1300_2, ~mu1299_4 +# 1300| r1300_3(int) = Load : &:r1300_2, ~m? # 1300| mu1300_4(int) = Store : &:r1300_1, r1300_3 # 1301| r1301_1(glval) = VariableAddress[b] : -# 1301| r1301_2(bool) = Load : &:r1301_1, ~mu1299_4 +# 1301| r1301_2(bool) = Load : &:r1301_1, ~m? # 1301| v1301_3(void) = ConditionalBranch : r1301_2 #-----| False -> Block 3 #-----| True -> Block 2 # 1301| Block 1 # 1301| r1301_4(glval) = VariableAddress[#temp1301:9] : -# 1301| r1301_5(int) = Load : &:r1301_4, ~mu1299_4 +# 1301| r1301_5(int) = Load : &:r1301_4, ~m? # 1301| r1301_6(glval) = VariableAddress[z] : # 1301| mu1301_7(int) = Store : &:r1301_6, r1301_5 # 1302| r1302_1(glval) = VariableAddress[b] : -# 1302| r1302_2(bool) = Load : &:r1302_1, ~mu1299_4 +# 1302| r1302_2(bool) = Load : &:r1302_1, ~m? # 1302| v1302_3(void) = ConditionalBranch : r1302_2 #-----| False -> Block 6 #-----| True -> Block 5 @@ -7298,19 +7169,19 @@ ir.cpp: # 1301| Block 3 # 1301| r1301_10(glval) = VariableAddress[x] : -# 1301| r1301_11(int) = Load : &:r1301_10, ~mu1299_4 +# 1301| r1301_11(int) = Load : &:r1301_10, ~m? # 1301| r1301_12(glval) = VariableAddress[#temp1301:9] : # 1301| mu1301_13(int) = Store : &:r1301_12, r1301_11 #-----| Goto -> Block 1 # 1302| Block 4 # 1302| r1302_4(glval) = VariableAddress[#temp1302:9] : -# 1302| r1302_5(long) = Load : &:r1302_4, ~mu1299_4 +# 1302| r1302_5(long) = Load : &:r1302_4, ~m? # 1302| r1302_6(int) = Convert : r1302_5 # 1302| r1302_7(glval) = VariableAddress[z] : # 1302| mu1302_8(int) = Store : &:r1302_7, r1302_6 # 1303| r1303_1(glval) = VariableAddress[x] : -# 1303| r1303_2(int) = Load : &:r1303_1, ~mu1299_4 +# 1303| r1303_2(int) = Load : &:r1303_1, ~m? # 1303| r1303_3(int) = Constant[0] : # 1303| r1303_4(bool) = CompareNE : r1303_2, r1303_3 # 1303| v1303_5(void) = ConditionalBranch : r1303_4 @@ -7324,18 +7195,18 @@ ir.cpp: # 1302| Block 6 # 1302| r1302_11(glval) = VariableAddress[y] : -# 1302| r1302_12(long) = Load : &:r1302_11, ~mu1299_4 +# 1302| r1302_12(long) = Load : &:r1302_11, ~m? # 1302| r1302_13(glval) = VariableAddress[#temp1302:9] : # 1302| mu1302_14(long) = Store : &:r1302_13, r1302_12 #-----| Goto -> Block 4 # 1303| Block 7 # 1303| r1303_6(glval) = VariableAddress[#temp1303:9] : -# 1303| r1303_7(int) = Load : &:r1303_6, ~mu1299_4 +# 1303| r1303_7(int) = Load : &:r1303_6, ~m? # 1303| r1303_8(glval) = VariableAddress[z] : # 1303| mu1303_9(int) = Store : &:r1303_8, r1303_7 # 1304| r1304_1(glval) = VariableAddress[x] : -# 1304| r1304_2(int) = Load : &:r1304_1, ~mu1299_4 +# 1304| r1304_2(int) = Load : &:r1304_1, ~m? # 1304| r1304_3(int) = Constant[0] : # 1304| r1304_4(bool) = CompareNE : r1304_2, r1304_3 # 1304| v1304_5(void) = ConditionalBranch : r1304_4 @@ -7349,19 +7220,19 @@ ir.cpp: # 1303| Block 9 # 1303| r1303_12(glval) = VariableAddress[x] : -# 1303| r1303_13(int) = Load : &:r1303_12, ~mu1299_4 +# 1303| r1303_13(int) = Load : &:r1303_12, ~m? # 1303| r1303_14(glval) = VariableAddress[#temp1303:9] : # 1303| mu1303_15(int) = Store : &:r1303_14, r1303_13 #-----| Goto -> Block 7 # 1304| Block 10 # 1304| r1304_6(glval) = VariableAddress[#temp1304:9] : -# 1304| r1304_7(long) = Load : &:r1304_6, ~mu1299_4 +# 1304| r1304_7(long) = Load : &:r1304_6, ~m? # 1304| r1304_8(int) = Convert : r1304_7 # 1304| r1304_9(glval) = VariableAddress[z] : # 1304| mu1304_10(int) = Store : &:r1304_9, r1304_8 # 1305| r1305_1(glval) = VariableAddress[y] : -# 1305| r1305_2(long) = Load : &:r1305_1, ~mu1299_4 +# 1305| r1305_2(long) = Load : &:r1305_1, ~m? # 1305| r1305_3(long) = Constant[0] : # 1305| r1305_4(bool) = CompareNE : r1305_2, r1305_3 # 1305| v1305_5(void) = ConditionalBranch : r1305_4 @@ -7375,19 +7246,19 @@ ir.cpp: # 1304| Block 12 # 1304| r1304_13(glval) = VariableAddress[y] : -# 1304| r1304_14(long) = Load : &:r1304_13, ~mu1299_4 +# 1304| r1304_14(long) = Load : &:r1304_13, ~m? # 1304| r1304_15(glval) = VariableAddress[#temp1304:9] : # 1304| mu1304_16(long) = Store : &:r1304_15, r1304_14 #-----| Goto -> Block 10 # 1305| Block 13 # 1305| r1305_6(glval) = VariableAddress[#temp1305:9] : -# 1305| r1305_7(long) = Load : &:r1305_6, ~mu1299_4 +# 1305| r1305_7(long) = Load : &:r1305_6, ~m? # 1305| r1305_8(int) = Convert : r1305_7 # 1305| r1305_9(glval) = VariableAddress[z] : # 1305| mu1305_10(int) = Store : &:r1305_9, r1305_8 # 1306| r1306_1(glval) = VariableAddress[y] : -# 1306| r1306_2(long) = Load : &:r1306_1, ~mu1299_4 +# 1306| r1306_2(long) = Load : &:r1306_1, ~m? # 1306| r1306_3(long) = Constant[0] : # 1306| r1306_4(bool) = CompareNE : r1306_2, r1306_3 # 1306| v1306_5(void) = ConditionalBranch : r1306_4 @@ -7401,7 +7272,7 @@ ir.cpp: # 1305| Block 15 # 1305| r1305_13(glval) = VariableAddress[x] : -# 1305| r1305_14(int) = Load : &:r1305_13, ~mu1299_4 +# 1305| r1305_14(int) = Load : &:r1305_13, ~m? # 1305| r1305_15(long) = Convert : r1305_14 # 1305| r1305_16(glval) = VariableAddress[#temp1305:9] : # 1305| mu1305_17(long) = Store : &:r1305_16, r1305_15 @@ -7409,12 +7280,12 @@ ir.cpp: # 1306| Block 16 # 1306| r1306_6(glval) = VariableAddress[#temp1306:9] : -# 1306| r1306_7(long) = Load : &:r1306_6, ~mu1299_4 +# 1306| r1306_7(long) = Load : &:r1306_6, ~m? # 1306| r1306_8(int) = Convert : r1306_7 # 1306| r1306_9(glval) = VariableAddress[z] : # 1306| mu1306_10(int) = Store : &:r1306_9, r1306_8 # 1308| r1308_1(glval) = VariableAddress[x] : -# 1308| r1308_2(int) = Load : &:r1308_1, ~mu1299_4 +# 1308| r1308_2(int) = Load : &:r1308_1, ~m? # 1308| r1308_3(int) = Constant[0] : # 1308| r1308_4(bool) = CompareNE : r1308_2, r1308_3 # 1308| v1308_5(void) = ConditionalBranch : r1308_4 @@ -7428,21 +7299,20 @@ ir.cpp: # 1306| Block 18 # 1306| r1306_13(glval) = VariableAddress[y] : -# 1306| r1306_14(long) = Load : &:r1306_13, ~mu1299_4 +# 1306| r1306_14(long) = Load : &:r1306_13, ~m? # 1306| r1306_15(glval) = VariableAddress[#temp1306:9] : # 1306| mu1306_16(long) = Store : &:r1306_15, r1306_14 #-----| Goto -> Block 16 # 1308| Block 19 # 1308| r1308_6(glval) = VariableAddress[#temp1308:9] : -# 1308| r1308_7(int) = Load : &:r1308_6, ~mu1299_4 +# 1308| r1308_7(int) = Load : &:r1308_6, ~m? # 1308| r1308_8(glval) = VariableAddress[z] : # 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 # 1309| v1309_1(void) = NoOp : -# 1299| v1299_11(void) = ReturnVoid : -# 1299| v1299_12(void) = UnmodeledUse : mu* -# 1299| v1299_13(void) = AliasedUse : ~mu1299_4 -# 1299| v1299_14(void) = ExitFunction : +# 1299| v1299_10(void) = ReturnVoid : +# 1299| v1299_11(void) = AliasedUse : ~m? +# 1299| v1299_12(void) = ExitFunction : # 1308| Block 20 # 1308| r1308_10(glval) = VariableAddress[#temp1308:9] : @@ -7457,7 +7327,7 @@ ir.cpp: # 1308| Block 22 # 1308| r1308_15(glval) = VariableAddress[#temp1308:10] : -# 1308| r1308_16(bool) = Load : &:r1308_15, ~mu1299_4 +# 1308| r1308_16(bool) = Load : &:r1308_15, ~m? # 1308| v1308_17(void) = ConditionalBranch : r1308_16 #-----| False -> Block 26 #-----| True -> Block 20 @@ -7470,14 +7340,14 @@ ir.cpp: # 1308| Block 24 # 1308| r1308_21(glval) = VariableAddress[b] : -# 1308| r1308_22(bool) = Load : &:r1308_21, ~mu1299_4 +# 1308| r1308_22(bool) = Load : &:r1308_21, ~m? # 1308| v1308_23(void) = ConditionalBranch : r1308_22 #-----| False -> Block 25 #-----| True -> Block 23 # 1308| Block 25 # 1308| r1308_24(glval) = VariableAddress[y] : -# 1308| r1308_25(long) = Load : &:r1308_24, ~mu1299_4 +# 1308| r1308_25(long) = Load : &:r1308_24, ~m? # 1308| r1308_26(long) = Constant[0] : # 1308| r1308_27(bool) = CompareNE : r1308_25, r1308_26 # 1308| v1308_28(void) = ConditionalBranch : r1308_27 @@ -7486,7 +7356,7 @@ ir.cpp: # 1308| Block 26 # 1308| r1308_29(glval) = VariableAddress[x] : -# 1308| r1308_30(int) = Load : &:r1308_29, ~mu1299_4 +# 1308| r1308_30(int) = Load : &:r1308_29, ~m? # 1308| r1308_31(glval) = VariableAddress[#temp1308:9] : # 1308| mu1308_32(int) = Store : &:r1308_31, r1308_30 #-----| Goto -> Block 19 @@ -7496,15 +7366,14 @@ ir.cpp: # 1314| v1314_1(void) = EnterFunction : # 1314| mu1314_2(unknown) = AliasedDefinition : # 1314| mu1314_3(unknown) = InitializeNonLocal : -# 1314| mu1314_4(unknown) = UnmodeledDefinition : -# 1314| r1314_5(glval) = VariableAddress[x] : -# 1314| mu1314_6(int) = InitializeParameter[x] : &:r1314_5 -# 1314| r1314_7(glval) = VariableAddress[y] : -# 1314| mu1314_8(int) = InitializeParameter[y] : &:r1314_7 +# 1314| r1314_4(glval) = VariableAddress[x] : +# 1314| mu1314_5(int) = InitializeParameter[x] : &:r1314_4 +# 1314| r1314_6(glval) = VariableAddress[y] : +# 1314| mu1314_7(int) = InitializeParameter[y] : &:r1314_6 # 1315| r1315_1(glval) = VariableAddress[#return] : # 1315| r1315_2(glval) = FunctionAddress[predicateA] : # 1315| r1315_3(bool) = Call : func:r1315_2 -# 1315| mu1315_4(unknown) = ^CallSideEffect : ~mu1314_4 +# 1315| mu1315_4(unknown) = ^CallSideEffect : ~m? # 1315| v1315_5(void) = ConditionalBranch : r1315_3 #-----| False -> Block 3 #-----| True -> Block 1 @@ -7512,80 +7381,103 @@ ir.cpp: # 1315| Block 1 # 1315| r1315_6(glval) = FunctionAddress[predicateB] : # 1315| r1315_7(bool) = Call : func:r1315_6 -# 1315| mu1315_8(unknown) = ^CallSideEffect : ~mu1314_4 +# 1315| mu1315_8(unknown) = ^CallSideEffect : ~m? # 1315| v1315_9(void) = ConditionalBranch : r1315_7 #-----| False -> Block 3 #-----| True -> Block 2 # 1315| Block 2 # 1315| r1315_10(glval) = VariableAddress[x] : -# 1315| r1315_11(int) = Load : &:r1315_10, ~mu1314_4 +# 1315| r1315_11(int) = Load : &:r1315_10, ~m? # 1315| r1315_12(glval) = VariableAddress[#temp1315:12] : # 1315| mu1315_13(int) = Store : &:r1315_12, r1315_11 #-----| Goto -> Block 4 # 1315| Block 3 # 1315| r1315_14(glval) = VariableAddress[y] : -# 1315| r1315_15(int) = Load : &:r1315_14, ~mu1314_4 +# 1315| r1315_15(int) = Load : &:r1315_14, ~m? # 1315| r1315_16(glval) = VariableAddress[#temp1315:12] : # 1315| mu1315_17(int) = Store : &:r1315_16, r1315_15 #-----| Goto -> Block 4 # 1315| Block 4 # 1315| r1315_18(glval) = VariableAddress[#temp1315:12] : -# 1315| r1315_19(int) = Load : &:r1315_18, ~mu1314_4 +# 1315| r1315_19(int) = Load : &:r1315_18, ~m? # 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 -# 1314| r1314_9(glval) = VariableAddress[#return] : -# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~mu1314_4 -# 1314| v1314_11(void) = UnmodeledUse : mu* -# 1314| v1314_12(void) = AliasedUse : ~mu1314_4 -# 1314| v1314_13(void) = ExitFunction : +# 1314| r1314_8(glval) = VariableAddress[#return] : +# 1314| v1314_9(void) = ReturnValue : &:r1314_8, ~m? +# 1314| v1314_10(void) = AliasedUse : ~m? +# 1314| v1314_11(void) = ExitFunction : + +# 1320| void f(int*) +# 1320| Block 0 +# 1320| v1320_1(void) = EnterFunction : +# 1320| mu1320_2(unknown) = AliasedDefinition : +# 1320| mu1320_3(unknown) = InitializeNonLocal : +# 1320| r1320_4(glval) = VariableAddress[p] : +# 1320| mu1320_5(int *) = InitializeParameter[p] : &:r1320_4 +# 1320| r1320_6(int *) = Load : &:r1320_4, ~m? +# 1320| mu1320_7(unknown) = InitializeIndirection[p] : &:r1320_6 +# 1322| r1322_1(glval) = FunctionAddress[operator new] : +# 1322| r1322_2(unsigned long) = Constant[4] : +# 1322| r1322_3(glval) = VariableAddress[p] : +# 1322| r1322_4(int *) = Load : &:r1322_3, ~m? +# 1322| r1322_5(void *) = Convert : r1322_4 +# 1322| r1322_6(void *) = Call : func:r1322_1, 0:r1322_2, 1:r1322_5 +# 1322| mu1322_7(unknown) = ^CallSideEffect : ~m? +# 1322| mu1322_8(unknown) = ^InitializeDynamicAllocation : &:r1322_6 +# 1322| r1322_9(int *) = Convert : r1322_6 +# 1323| v1323_1(void) = NoOp : +# 1320| v1320_8(void) = ReturnIndirection[p] : &:r1320_6, ~m? +# 1320| v1320_9(void) = ReturnVoid : +# 1320| v1320_10(void) = AliasedUse : ~m? +# 1320| v1320_11(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 -# 6| v6_1(void) = EnterFunction : -# 6| mu6_2(unknown) = AliasedDefinition : -# 6| mu6_3(unknown) = InitializeNonLocal : -# 6| mu6_4(unknown) = UnmodeledDefinition : -# 6| r6_5(glval) = InitializeThis : -# 6| r6_6(glval) = FieldAddress[buffer] : r6_5 -# 6| r6_7(int) = Constant[0] : -# 6| r6_8(glval) = PointerAdd[1] : r6_6, r6_7 -# 6| r6_9(unknown[1073741824]) = Constant[0] : -# 6| mu6_10(unknown[1073741824]) = Store : &:r6_8, r6_9 -# 6| v6_11(void) = NoOp : -# 6| v6_12(void) = ReturnVoid : -# 6| v6_13(void) = UnmodeledUse : mu* -# 6| v6_14(void) = AliasedUse : ~mu6_4 -# 6| v6_15(void) = ExitFunction : +# 6| v6_1(void) = EnterFunction : +# 6| mu6_2(unknown) = AliasedDefinition : +# 6| mu6_3(unknown) = InitializeNonLocal : +# 6| r6_4(glval) = VariableAddress[#this] : +# 6| mu6_5(glval) = InitializeParameter[#this] : &:r6_4 +# 6| r6_6(glval) = Load : &:r6_4, ~m? +# 6| mu6_7(Big) = InitializeIndirection[#this] : &:r6_6 +# 6| r6_8(glval) = FieldAddress[buffer] : mu6_5 +# 6| r6_9(int) = Constant[0] : +# 6| r6_10(glval) = PointerAdd[1] : r6_8, r6_9 +# 6| r6_11(unknown[1073741824]) = Constant[0] : +# 6| mu6_12(unknown[1073741824]) = Store : &:r6_10, r6_11 +# 6| v6_13(void) = NoOp : +# 6| v6_14(void) = ReturnIndirection[#this] : &:r6_6, ~m? +# 6| v6_15(void) = ReturnVoid : +# 6| v6_16(void) = AliasedUse : ~m? +# 6| v6_17(void) = ExitFunction : # 9| int main() # 9| Block 0 # 9| v9_1(void) = EnterFunction : # 9| mu9_2(unknown) = AliasedDefinition : # 9| mu9_3(unknown) = InitializeNonLocal : -# 9| mu9_4(unknown) = UnmodeledDefinition : # 10| r10_1(glval) = VariableAddress[big] : # 10| r10_2(glval) = FunctionAddress[operator new] : # 10| r10_3(unsigned long) = Constant[1073741824] : # 10| r10_4(void *) = Call : func:r10_2, 0:r10_3 -# 10| mu10_5(unknown) = ^CallSideEffect : ~mu9_4 +# 10| mu10_5(unknown) = ^CallSideEffect : ~m? # 10| mu10_6(unknown) = ^InitializeDynamicAllocation : &:r10_4 # 10| r10_7(Big *) = Convert : r10_4 # 10| r10_8(glval) = FunctionAddress[Big] : # 10| v10_9(void) = Call : func:r10_8, this:r10_7 -# 10| mu10_10(unknown) = ^CallSideEffect : ~mu9_4 +# 10| mu10_10(unknown) = ^CallSideEffect : ~m? # 10| mu10_11(Big) = ^IndirectMayWriteSideEffect[-1] : &:r10_7 # 10| mu10_12(Big *) = Store : &:r10_1, r10_7 # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2(int) = Constant[0] : # 12| mu12_3(int) = Store : &:r12_1, r12_2 -# 9| r9_5(glval) = VariableAddress[#return] : -# 9| v9_6(void) = ReturnValue : &:r9_5, ~mu9_4 -# 9| v9_7(void) = UnmodeledUse : mu* -# 9| v9_8(void) = AliasedUse : ~mu9_4 -# 9| v9_9(void) = ExitFunction : +# 9| r9_4(glval) = VariableAddress[#return] : +# 9| v9_5(void) = ReturnValue : &:r9_4, ~m? +# 9| v9_6(void) = AliasedUse : ~m? +# 9| v9_7(void) = ExitFunction : struct_init.cpp: # 16| void let_info_escape(Info*) @@ -7593,47 +7485,42 @@ struct_init.cpp: # 16| v16_1(void) = EnterFunction : # 16| mu16_2(unknown) = AliasedDefinition : # 16| mu16_3(unknown) = InitializeNonLocal : -# 16| mu16_4(unknown) = UnmodeledDefinition : -# 16| r16_5(glval) = VariableAddress[info] : -# 16| mu16_6(Info *) = InitializeParameter[info] : &:r16_5 -# 16| r16_7(Info *) = Load : &:r16_5, ~mu16_4 -# 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7 +# 16| r16_4(glval) = VariableAddress[info] : +# 16| mu16_5(Info *) = InitializeParameter[info] : &:r16_4 +# 16| r16_6(Info *) = Load : &:r16_4, ~m? +# 16| mu16_7(unknown) = InitializeIndirection[info] : &:r16_6 # 17| r17_1(glval) = VariableAddress[info] : -# 17| r17_2(Info *) = Load : &:r17_1, ~mu16_4 +# 17| r17_2(Info *) = Load : &:r17_1, ~m? # 17| r17_3(glval) = VariableAddress[global_pointer] : # 17| mu17_4(Info *) = Store : &:r17_3, r17_2 # 18| v18_1(void) = NoOp : -# 16| v16_9(void) = ReturnIndirection[info] : &: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 : +# 16| v16_8(void) = ReturnIndirection[info] : &:r16_6, ~m? +# 16| v16_9(void) = ReturnVoid : +# 16| v16_10(void) = AliasedUse : ~m? +# 16| v16_11(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 : # 25| r25_1(glval) = FunctionAddress[let_info_escape] : # 25| r25_2(glval) = 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_5(unknown) = ^CallSideEffect : ~m? +# 25| v25_6(void) = ^BufferReadSideEffect[0] : &:r25_3, ~m? # 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 : +# 20| v20_4(void) = ReturnVoid : +# 20| v20_5(void) = AliasedUse : ~m? +# 20| v20_6(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) = VariableAddress[local_infos] : # 29| mu29_2(Info[2]) = Uninitialized[local_infos] : &:r29_1 # 29| r29_3(int) = Constant[0] : @@ -7659,27 +7546,25 @@ struct_init.cpp: # 33| r33_2(glval) = 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_5(unknown) = ^CallSideEffect : ~m? +# 33| v33_6(void) = ^BufferReadSideEffect[0] : &:r33_3, ~m? # 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 : +# 28| v28_4(void) = ReturnVoid : +# 28| v28_5(void) = AliasedUse : ~m? +# 28| v28_6(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) = VariableAddress[name1] : -# 36| mu36_6(char *) = InitializeParameter[name1] : &:r36_5 -# 36| r36_7(char *) = Load : &:r36_5, ~mu36_4 -# 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7 +# 36| r36_4(glval) = VariableAddress[name1] : +# 36| mu36_5(char *) = InitializeParameter[name1] : &:r36_4 +# 36| r36_6(char *) = Load : &:r36_4, ~m? +# 36| mu36_7(unknown) = InitializeIndirection[name1] : &:r36_6 # 37| r37_1(glval) = VariableAddress[static_infos#init] : -# 37| r37_2(bool) = Load : &:r37_1, ~mu36_4 +# 37| r37_2(bool) = Load : &:r37_1, ~m? # 37| v37_3(void) = ConditionalBranch : r37_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -7689,15 +7574,14 @@ struct_init.cpp: # 41| r41_2(glval) = 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_5(unknown) = ^CallSideEffect : ~m? +# 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~m? # 41| mu41_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r41_3 # 42| v42_1(void) = NoOp : -# 36| v36_9(void) = ReturnIndirection[name1] : &: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 : +# 36| v36_8(void) = ReturnIndirection[name1] : &:r36_6, ~m? +# 36| v36_9(void) = ReturnVoid : +# 36| v36_10(void) = AliasedUse : ~m? +# 36| v36_11(void) = ExitFunction : # 37| Block 2 # 37| r37_4(glval) = VariableAddress[static_infos] : @@ -7705,7 +7589,7 @@ struct_init.cpp: # 37| r37_6(glval) = PointerAdd[16] : r37_4, r37_5 # 38| r38_1(glval) = FieldAddress[name] : r37_6 # 38| r38_2(glval) = VariableAddress[name1] : -# 38| r38_3(char *) = Load : &:r38_2, ~mu36_4 +# 38| r38_3(char *) = Load : &:r38_2, ~m? # 38| mu38_4(char *) = Store : &:r38_1, r38_3 # 38| r38_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_6 # 38| r38_6(..(*)(..)) = FunctionAddress[handler1] : diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref b/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref deleted file mode 100644 index 959b466103c..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected similarity index 82% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql new file mode 100644 index 00000000000..6507642d86a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected new file mode 100644 index 00000000000..64172ad1873 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -0,0 +1,32 @@ +missingOperand +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes +missingCppType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql deleted file mode 100644 index c7d0ba957af..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected deleted file mode 100644 index 3a1a30265b2..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected +++ /dev/null @@ -1,31 +0,0 @@ -missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes -missingCppType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected similarity index 62% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql similarity index 89% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql index 120881bf018..97800ca6e80 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected similarity index 62% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..fd03efbc267 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 18bf9212dbf..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected similarity index 95% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql new file mode 100644 index 00000000000..847991163c8 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected similarity index 95% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 8fdffc0569a..43b8116d85f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -5,56 +5,55 @@ ssa.cpp: # 13| m13_2(unknown) = AliasedDefinition : # 13| m13_3(unknown) = InitializeNonLocal : # 13| m13_4(unknown) = Chi : total:m13_2, partial:m13_3 -# 13| mu13_5(unknown) = UnmodeledDefinition : -# 13| r13_6(glval) = VariableAddress[p] : -# 13| m13_7(Point *) = InitializeParameter[p] : &:r13_6 -# 13| r13_8(Point *) = Load : &:r13_6, m13_7 -# 13| m13_9(unknown) = InitializeIndirection[p] : &:r13_8 -# 13| r13_10(glval) = VariableAddress[which1] : -# 13| m13_11(bool) = InitializeParameter[which1] : &:r13_10 -# 13| r13_12(glval) = VariableAddress[which2] : -# 13| m13_13(bool) = InitializeParameter[which2] : &:r13_12 +# 13| r13_5(glval) = VariableAddress[p] : +# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 +# 13| r13_7(Point *) = Load : &:r13_5, m13_6 +# 13| m13_8(unknown) = InitializeIndirection[p] : &:r13_7 +# 13| r13_9(glval) = VariableAddress[which1] : +# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 +# 13| r13_11(glval) = VariableAddress[which2] : +# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_11 +# 14| r14_2(bool) = Load : &:r14_1, m13_10 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_7 +# 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~m13_9 +# 15| r15_4(int) = Load : &:r15_3, ~m13_8 # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| m15_7(int) = Store : &:r15_3, r15_6 -# 15| m15_8(unknown) = Chi : total:m13_9, partial:m15_7 +# 15| m15_8(unknown) = Chi : total:m13_8, partial:m15_7 #-----| Goto -> Block 3 # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_7 +# 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~m13_9 +# 18| r18_4(int) = Load : &:r18_3, ~m13_8 # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| m18_7(int) = Store : &:r18_3, r18_6 -# 18| m18_8(unknown) = Chi : total:m13_9, partial:m18_7 +# 18| m18_8(unknown) = Chi : total:m13_8, partial:m18_7 #-----| Goto -> Block 3 # 21| Block 3 -# 21| m21_1(int) = Phi : from 1:~m13_9, from 2:m18_7 -# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_9 +# 21| m21_1(int) = Phi : from 1:~m13_8, from 2:m18_7 +# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_8 # 21| m21_3(unknown) = Phi : from 1:m15_8, from 2:m18_8 # 21| r21_4(glval) = VariableAddress[which2] : -# 21| r21_5(bool) = Load : &:r21_4, m13_13 +# 21| r21_5(bool) = Load : &:r21_4, m13_12 # 21| v21_6(void) = ConditionalBranch : r21_5 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_7 +# 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, m21_2 # 22| r22_5(int) = Constant[1] : @@ -65,7 +64,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_7 +# 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, m21_1 # 25| r25_5(int) = Constant[1] : @@ -80,21 +79,20 @@ ssa.cpp: # 28| m28_3(unknown) = Phi : from 4:m22_8, from 5:m25_8 # 28| r28_4(glval) = VariableAddress[#return] : # 28| r28_5(glval) = VariableAddress[p] : -# 28| r28_6(Point *) = Load : &:r28_5, m13_7 +# 28| r28_6(Point *) = Load : &:r28_5, m13_6 # 28| r28_7(glval) = FieldAddress[x] : r28_6 # 28| r28_8(int) = Load : &:r28_7, m28_2 # 28| r28_9(glval) = VariableAddress[p] : -# 28| r28_10(Point *) = Load : &:r28_9, m13_7 +# 28| r28_10(Point *) = Load : &:r28_9, m13_6 # 28| r28_11(glval) = FieldAddress[y] : r28_10 # 28| r28_12(int) = Load : &:r28_11, m28_1 # 28| r28_13(int) = Add : r28_8, r28_12 # 28| m28_14(int) = Store : &:r28_4, r28_13 -# 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 -# 13| r13_15(glval) = VariableAddress[#return] : -# 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = UnmodeledUse : mu* -# 13| v13_18(void) = AliasedUse : m13_3 -# 13| v13_19(void) = ExitFunction : +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, m28_3 +# 13| r13_14(glval) = VariableAddress[#return] : +# 13| v13_15(void) = ReturnValue : &:r13_14, m28_14 +# 13| v13_16(void) = AliasedUse : m13_3 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -102,17 +100,15 @@ ssa.cpp: # 31| m31_2(unknown) = AliasedDefinition : # 31| m31_3(unknown) = InitializeNonLocal : # 31| m31_4(unknown) = Chi : total:m31_2, partial:m31_3 -# 31| mu31_5(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_6(glval) = VariableAddress[#return] : -# 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = UnmodeledUse : mu* -# 31| v31_9(void) = AliasedUse : m31_3 -# 31| v31_10(void) = ExitFunction : +# 31| r31_5(glval) = VariableAddress[#return] : +# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 +# 31| v31_7(void) = AliasedUse : m31_3 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -120,9 +116,8 @@ ssa.cpp: # 38| m38_2(unknown) = AliasedDefinition : # 38| m38_3(unknown) = InitializeNonLocal : # 38| m38_4(unknown) = Chi : total:m38_2, partial:m38_3 -# 38| mu38_5(unknown) = UnmodeledDefinition : -# 38| r38_6(glval) = VariableAddress[b] : -# 38| m38_7(bool) = InitializeParameter[b] : &:r38_6 +# 38| r38_5(glval) = VariableAddress[b] : +# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -130,18 +125,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_7 +# 41| r41_2(bool) = Load : &:r41_1, m38_6 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 4 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 -# 38| r38_9(glval) = VariableAddress[#return] : -# 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = UnmodeledUse : mu* -# 38| v38_12(void) = AliasedUse : m38_3 -# 38| v38_13(void) = ExitFunction : +# 38| m38_7(int) = Phi : from 3:m46_3, from 5:m51_3 +# 38| r38_8(glval) = VariableAddress[#return] : +# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 +# 38| v38_10(void) = AliasedUse : m38_3 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,25 +170,24 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_14(void) = Unreached : +# 38| v38_12(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| m59_2(unknown) = AliasedDefinition : -# 59| m59_3(unknown) = InitializeNonLocal : -# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 -# 59| mu59_5(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| m59_2(unknown) = AliasedDefinition : +# 59| m59_3(unknown) = InitializeNonLocal : +# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -203,14 +196,13 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_6(glval) = VariableAddress[#return] : -# 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = UnmodeledUse : mu* -# 59| v59_9(void) = AliasedUse : m59_3 -# 59| v59_10(void) = ExitFunction : +# 59| r59_5(glval) = VariableAddress[#return] : +# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 +# 59| v59_7(void) = AliasedUse : m59_3 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_11(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -218,18 +210,17 @@ ssa.cpp: # 68| m68_2(unknown) = AliasedDefinition : # 68| m68_3(unknown) = InitializeNonLocal : # 68| m68_4(unknown) = Chi : total:m68_2, partial:m68_3 -# 68| mu68_5(unknown) = UnmodeledDefinition : -# 68| r68_6(glval) = VariableAddress[n] : -# 68| m68_7(int) = InitializeParameter[n] : &:r68_6 -# 68| r68_8(glval) = VariableAddress[p] : -# 68| m68_9(char *) = InitializeParameter[p] : &:r68_8 -# 68| r68_10(char *) = Load : &:r68_8, m68_9 -# 68| m68_11(unknown) = InitializeIndirection[p] : &:r68_10 +# 68| r68_5(glval) = VariableAddress[n] : +# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 +# 68| r68_7(glval) = VariableAddress[p] : +# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 +# 68| r68_9(char *) = Load : &:r68_7, m68_8 +# 68| m68_10(unknown) = InitializeIndirection[p] : &:r68_9 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_9, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_7, from 2:m69_8 +# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_8 # 69| m69_3(unknown) = Phi : from 0:~m68_4, from 2:~m70_10 # 69| r69_4(glval) = VariableAddress[n] : # 69| r69_5(int) = Load : &:r69_4, m69_2 @@ -258,11 +249,10 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 -# 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = UnmodeledUse : mu* -# 68| v68_15(void) = AliasedUse : ~m69_3 -# 68| v68_16(void) = ExitFunction : +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10 +# 68| v68_12(void) = ReturnVoid : +# 68| v68_13(void) = AliasedUse : ~m69_3 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -270,9 +260,8 @@ ssa.cpp: # 75| m75_2(unknown) = AliasedDefinition : # 75| m75_3(unknown) = InitializeNonLocal : # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| r75_6(glval) = VariableAddress[b] : -# 75| m75_7(bool) = InitializeParameter[b] : &:r75_6 +# 75| r75_5(glval) = VariableAddress[b] : +# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -283,7 +272,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_7 +# 79| r79_2(bool) = Load : &:r79_1, m75_6 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -319,10 +308,9 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = UnmodeledUse : mu* -# 75| v75_10(void) = AliasedUse : m75_3 -# 75| v75_11(void) = ExitFunction : +# 75| v75_7(void) = ReturnVoid : +# 75| v75_8(void) = AliasedUse : m75_3 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -330,18 +318,16 @@ ssa.cpp: # 91| m91_2(unknown) = AliasedDefinition : # 91| m91_3(unknown) = InitializeNonLocal : # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| r91_6(glval) = VariableAddress[a] : -# 91| m91_7(Point) = InitializeParameter[a] : &:r91_6 +# 91| r91_5(glval) = VariableAddress[a] : +# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_7 +# 92| r92_3(Point) = Load : &:r92_2, m91_6 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = UnmodeledUse : mu* -# 91| v91_10(void) = AliasedUse : m91_3 -# 91| v91_11(void) = ExitFunction : +# 91| v91_7(void) = ReturnVoid : +# 91| v91_8(void) = AliasedUse : m91_3 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -349,29 +335,27 @@ ssa.cpp: # 95| m95_2(unknown) = AliasedDefinition : # 95| m95_3(unknown) = InitializeNonLocal : # 95| m95_4(unknown) = Chi : total:m95_2, partial:m95_3 -# 95| mu95_5(unknown) = UnmodeledDefinition : -# 95| r95_6(glval) = VariableAddress[a] : -# 95| m95_7(Point) = InitializeParameter[a] : &:r95_6 -# 95| m95_8(unknown) = Chi : total:m95_4, partial:m95_7 +# 95| r95_5(glval) = VariableAddress[a] : +# 95| m95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| m95_7(unknown) = Chi : total:m95_4, partial:m95_6 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, m95_7 +# 96| r96_3(Point) = Load : &:r96_2, m95_6 # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| m97_6(unknown) = ^CallSideEffect : ~m95_8 -# 97| m97_7(unknown) = Chi : total:m95_8, partial:m97_6 +# 97| m97_6(unknown) = ^CallSideEffect : ~m95_7 +# 97| m97_7(unknown) = Chi : total:m95_7, partial:m97_6 # 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m97_7 # 97| m97_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 97| m97_10(unknown) = Chi : total:m97_7, partial:m97_9 # 98| v98_1(void) = NoOp : -# 95| v95_9(void) = ReturnVoid : -# 95| v95_10(void) = UnmodeledUse : mu* -# 95| v95_11(void) = AliasedUse : ~m97_7 -# 95| v95_12(void) = ExitFunction : +# 95| v95_8(void) = ReturnVoid : +# 95| v95_9(void) = AliasedUse : ~m97_7 +# 95| v95_10(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -379,24 +363,22 @@ ssa.cpp: # 100| m100_2(unknown) = AliasedDefinition : # 100| m100_3(unknown) = InitializeNonLocal : # 100| m100_4(unknown) = Chi : total:m100_2, partial:m100_3 -# 100| mu100_5(unknown) = UnmodeledDefinition : -# 100| r100_6(glval) = VariableAddress[a] : -# 100| m100_7(Point) = InitializeParameter[a] : &:r100_6 +# 100| r100_5(glval) = VariableAddress[a] : +# 100| m100_6(Point) = InitializeParameter[a] : &:r100_5 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~m100_7 +# 101| r101_4(int) = Load : &:r101_3, ~m100_6 # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~m100_7 +# 102| r102_4(int) = Load : &:r102_3, ~m100_6 # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = UnmodeledUse : mu* -# 100| v100_10(void) = AliasedUse : m100_3 -# 100| v100_11(void) = ExitFunction : +# 100| v100_7(void) = ReturnVoid : +# 100| v100_8(void) = AliasedUse : m100_3 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -404,35 +386,33 @@ ssa.cpp: # 105| m105_2(unknown) = AliasedDefinition : # 105| m105_3(unknown) = InitializeNonLocal : # 105| m105_4(unknown) = Chi : total:m105_2, partial:m105_3 -# 105| mu105_5(unknown) = UnmodeledDefinition : -# 105| r105_6(glval) = VariableAddress[a] : -# 105| m105_7(Point) = InitializeParameter[a] : &:r105_6 -# 105| m105_8(unknown) = Chi : total:m105_4, partial:m105_7 +# 105| r105_5(glval) = VariableAddress[a] : +# 105| m105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| m105_7(unknown) = Chi : total:m105_4, partial:m105_6 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~m105_7 +# 106| r106_4(int) = Load : &:r106_3, ~m105_6 # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~m105_7 +# 107| r107_4(int) = Load : &:r107_3, ~m105_6 # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| m108_6(unknown) = ^CallSideEffect : ~m105_8 -# 108| m108_7(unknown) = Chi : total:m105_8, partial:m108_6 +# 108| m108_6(unknown) = ^CallSideEffect : ~m105_7 +# 108| m108_7(unknown) = Chi : total:m105_7, partial:m108_6 # 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m108_7 # 108| m108_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 108| m108_10(unknown) = Chi : total:m108_7, partial:m108_9 # 109| v109_1(void) = NoOp : -# 105| v105_9(void) = ReturnVoid : -# 105| v105_10(void) = UnmodeledUse : mu* -# 105| v105_11(void) = AliasedUse : ~m108_7 -# 105| v105_12(void) = ExitFunction : +# 105| v105_8(void) = ReturnVoid : +# 105| v105_9(void) = AliasedUse : ~m108_7 +# 105| v105_10(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -440,21 +420,20 @@ ssa.cpp: # 111| m111_2(unknown) = AliasedDefinition : # 111| m111_3(unknown) = InitializeNonLocal : # 111| m111_4(unknown) = Chi : total:m111_2, partial:m111_3 -# 111| mu111_5(unknown) = UnmodeledDefinition : -# 111| r111_6(glval) = VariableAddress[x] : -# 111| m111_7(int) = InitializeParameter[x] : &:r111_6 -# 111| r111_8(glval) = VariableAddress[y] : -# 111| m111_9(int) = InitializeParameter[y] : &:r111_8 +# 111| r111_5(glval) = VariableAddress[x] : +# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 +# 111| r111_7(glval) = VariableAddress[y] : +# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 # 112| r112_1(glval) = VariableAddress[a] : # 112| m112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_7 +# 112| r112_5(int) = Load : &:r112_4, m111_6 # 112| m112_6(int) = Store : &:r112_3, r112_5 # 112| m112_7(Point) = Chi : total:m112_2, partial:m112_6 # 112| r112_8(glval) = FieldAddress[y] : r112_1 # 112| r112_9(glval) = VariableAddress[y] : -# 112| r112_10(int) = Load : &:r112_9, m111_9 +# 112| r112_10(int) = Load : &:r112_9, m111_8 # 112| m112_11(int) = Store : &:r112_8, r112_10 # 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11 # 113| r113_1(glval) = VariableAddress[b] : @@ -462,10 +441,9 @@ ssa.cpp: # 113| r113_3(Point) = Load : &:r113_2, m112_12 # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = UnmodeledUse : mu* -# 111| v111_12(void) = AliasedUse : m111_3 -# 111| v111_13(void) = ExitFunction : +# 111| v111_9(void) = ReturnVoid : +# 111| v111_10(void) = AliasedUse : m111_3 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -473,22 +451,21 @@ ssa.cpp: # 116| m116_2(unknown) = AliasedDefinition : # 116| m116_3(unknown) = InitializeNonLocal : # 116| m116_4(unknown) = Chi : total:m116_2, partial:m116_3 -# 116| mu116_5(unknown) = UnmodeledDefinition : -# 116| r116_6(glval) = VariableAddress[x] : -# 116| m116_7(int) = InitializeParameter[x] : &:r116_6 -# 116| r116_8(glval) = VariableAddress[y] : -# 116| m116_9(int) = InitializeParameter[y] : &:r116_8 +# 116| r116_5(glval) = VariableAddress[x] : +# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 +# 116| r116_7(glval) = VariableAddress[y] : +# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 # 117| r117_1(glval) = VariableAddress[a] : # 117| m117_2(Point) = Uninitialized[a] : &:r117_1 # 117| m117_3(unknown) = Chi : total:m116_4, partial:m117_2 # 117| r117_4(glval) = FieldAddress[x] : r117_1 # 117| r117_5(glval) = VariableAddress[x] : -# 117| r117_6(int) = Load : &:r117_5, m116_7 +# 117| r117_6(int) = Load : &:r117_5, m116_6 # 117| m117_7(int) = Store : &:r117_4, r117_6 # 117| m117_8(unknown) = Chi : total:m117_3, partial:m117_7 # 117| r117_9(glval) = FieldAddress[y] : r117_1 # 117| r117_10(glval) = VariableAddress[y] : -# 117| r117_11(int) = Load : &:r117_10, m116_9 +# 117| r117_11(int) = Load : &:r117_10, m116_8 # 117| m117_12(int) = Store : &:r117_9, r117_11 # 117| m117_13(unknown) = Chi : total:m117_8, partial:m117_12 # 118| r118_1(glval) = VariableAddress[b] : @@ -506,10 +483,9 @@ ssa.cpp: # 119| m119_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 119| m119_10(unknown) = Chi : total:m119_7, partial:m119_9 # 120| v120_1(void) = NoOp : -# 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = UnmodeledUse : mu* -# 116| v116_12(void) = AliasedUse : ~m119_7 -# 116| v116_13(void) = ExitFunction : +# 116| v116_9(void) = ReturnVoid : +# 116| v116_10(void) = AliasedUse : ~m119_7 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -517,13 +493,12 @@ ssa.cpp: # 122| m122_2(unknown) = AliasedDefinition : # 122| m122_3(unknown) = InitializeNonLocal : # 122| m122_4(unknown) = Chi : total:m122_2, partial:m122_3 -# 122| mu122_5(unknown) = UnmodeledDefinition : -# 122| r122_6(glval) = VariableAddress[c] : -# 122| m122_7(bool) = InitializeParameter[c] : &:r122_6 -# 122| r122_8(glval) = VariableAddress[x1] : -# 122| m122_9(int) = InitializeParameter[x1] : &:r122_8 -# 122| r122_10(glval) = VariableAddress[x2] : -# 122| m122_11(int) = InitializeParameter[x2] : &:r122_10 +# 122| r122_5(glval) = VariableAddress[c] : +# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 +# 122| r122_7(glval) = VariableAddress[x1] : +# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 +# 122| r122_9(glval) = VariableAddress[x2] : +# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 # 123| r123_1(glval) = VariableAddress[a] : # 123| m123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -535,14 +510,14 @@ ssa.cpp: # 123| m123_9(int) = Store : &:r123_7, r123_8 # 123| m123_10(Point) = Chi : total:m123_6, partial:m123_9 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_7 +# 124| r124_2(bool) = Load : &:r124_1, m122_6 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_9 +# 125| r125_2(int) = Load : &:r125_1, m122_8 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| m125_5(int) = Store : &:r125_4, r125_2 @@ -551,7 +526,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_11 +# 128| r128_2(int) = Load : &:r128_1, m122_10 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| m128_5(int) = Store : &:r128_4, r128_2 @@ -571,10 +546,9 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, m130_2 # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = UnmodeledUse : mu* -# 122| v122_14(void) = AliasedUse : m122_3 -# 122| v122_15(void) = ExitFunction : +# 122| v122_11(void) = ReturnVoid : +# 122| v122_12(void) = AliasedUse : m122_3 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -582,13 +556,12 @@ ssa.cpp: # 134| m134_2(unknown) = AliasedDefinition : # 134| m134_3(unknown) = InitializeNonLocal : # 134| m134_4(unknown) = Chi : total:m134_2, partial:m134_3 -# 134| mu134_5(unknown) = UnmodeledDefinition : -# 134| r134_6(glval) = VariableAddress[c] : -# 134| m134_7(bool) = InitializeParameter[c] : &:r134_6 -# 134| r134_8(glval) = VariableAddress[p] : -# 134| m134_9(Point) = InitializeParameter[p] : &:r134_8 -# 134| r134_10(glval) = VariableAddress[x1] : -# 134| m134_11(int) = InitializeParameter[x1] : &:r134_10 +# 134| r134_5(glval) = VariableAddress[c] : +# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 +# 134| r134_7(glval) = VariableAddress[p] : +# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 +# 134| r134_9(glval) = VariableAddress[x1] : +# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 # 135| r135_1(glval) = VariableAddress[a] : # 135| m135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -600,14 +573,14 @@ ssa.cpp: # 135| m135_9(int) = Store : &:r135_7, r135_8 # 135| m135_10(Point) = Chi : total:m135_6, partial:m135_9 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_7 +# 136| r136_2(bool) = Load : &:r136_1, m134_6 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_11 +# 137| r137_2(int) = Load : &:r137_1, m134_10 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| m137_5(int) = Store : &:r137_4, r137_2 @@ -616,7 +589,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_9 +# 140| r140_2(Point) = Load : &:r140_1, m134_8 # 140| r140_3(glval) = VariableAddress[a] : # 140| m140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -630,10 +603,9 @@ ssa.cpp: # 142| r142_6(int) = Load : &:r142_5, m142_1 # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : -# 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = UnmodeledUse : mu* -# 134| v134_14(void) = AliasedUse : m134_3 -# 134| v134_15(void) = ExitFunction : +# 134| v134_11(void) = ReturnVoid : +# 134| v134_12(void) = AliasedUse : m134_3 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -641,13 +613,12 @@ ssa.cpp: # 145| m145_2(unknown) = AliasedDefinition : # 145| m145_3(unknown) = InitializeNonLocal : # 145| m145_4(unknown) = Chi : total:m145_2, partial:m145_3 -# 145| mu145_5(unknown) = UnmodeledDefinition : -# 145| r145_6(glval) = VariableAddress[c] : -# 145| m145_7(bool) = InitializeParameter[c] : &:r145_6 -# 145| r145_8(glval) = VariableAddress[p] : -# 145| m145_9(Point) = InitializeParameter[p] : &:r145_8 -# 145| r145_10(glval) = VariableAddress[x1] : -# 145| m145_11(int) = InitializeParameter[x1] : &:r145_10 +# 145| r145_5(glval) = VariableAddress[c] : +# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 +# 145| r145_7(glval) = VariableAddress[p] : +# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 +# 145| r145_9(glval) = VariableAddress[x1] : +# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 # 146| r146_1(glval) = VariableAddress[a] : # 146| m146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -659,14 +630,14 @@ ssa.cpp: # 146| m146_9(int) = Store : &:r146_7, r146_8 # 146| m146_10(Point) = Chi : total:m146_6, partial:m146_9 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_7 +# 147| r147_2(bool) = Load : &:r147_1, m145_6 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_11 +# 148| r148_2(int) = Load : &:r148_1, m145_10 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| m148_5(int) = Store : &:r148_4, r148_2 @@ -675,7 +646,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_9 +# 151| r151_2(Point) = Load : &:r151_1, m145_8 # 151| r151_3(glval) = VariableAddress[a] : # 151| m151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -687,10 +658,9 @@ ssa.cpp: # 153| r153_4(Point) = Load : &:r153_3, m153_1 # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : -# 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = UnmodeledUse : mu* -# 145| v145_14(void) = AliasedUse : m145_3 -# 145| v145_15(void) = ExitFunction : +# 145| v145_11(void) = ReturnVoid : +# 145| v145_12(void) = AliasedUse : m145_3 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -698,13 +668,12 @@ ssa.cpp: # 156| m156_2(unknown) = AliasedDefinition : # 156| m156_3(unknown) = InitializeNonLocal : # 156| m156_4(unknown) = Chi : total:m156_2, partial:m156_3 -# 156| mu156_5(unknown) = UnmodeledDefinition : -# 156| r156_6(glval) = VariableAddress[c] : -# 156| m156_7(bool) = InitializeParameter[c] : &:r156_6 -# 156| r156_8(glval) = VariableAddress[r] : -# 156| m156_9(Rect) = InitializeParameter[r] : &:r156_8 -# 156| r156_10(glval) = VariableAddress[x1] : -# 156| m156_11(int) = InitializeParameter[x1] : &:r156_10 +# 156| r156_5(glval) = VariableAddress[c] : +# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 +# 156| r156_7(glval) = VariableAddress[r] : +# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 +# 156| r156_9(glval) = VariableAddress[x1] : +# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 # 157| r157_1(glval) = VariableAddress[a] : # 157| m157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -716,14 +685,14 @@ ssa.cpp: # 157| m157_9(Point) = Store : &:r157_7, r157_8 # 157| m157_10(Rect) = Chi : total:m157_6, partial:m157_9 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_7 +# 158| r158_2(bool) = Load : &:r158_1, m156_6 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_11 +# 159| r159_2(int) = Load : &:r159_1, m156_10 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -733,7 +702,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_9 +# 162| r162_2(Rect) = Load : &:r162_1, m156_8 # 162| r162_3(glval) = VariableAddress[a] : # 162| m162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -746,10 +715,9 @@ ssa.cpp: # 164| r164_5(Point) = Load : &:r164_4, ~m164_1 # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : -# 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = UnmodeledUse : mu* -# 156| v156_14(void) = AliasedUse : m156_3 -# 156| v156_15(void) = ExitFunction : +# 156| v156_11(void) = ReturnVoid : +# 156| v156_12(void) = AliasedUse : m156_3 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -757,17 +725,16 @@ ssa.cpp: # 171| m171_2(unknown) = AliasedDefinition : # 171| m171_3(unknown) = InitializeNonLocal : # 171| m171_4(unknown) = Chi : total:m171_2, partial:m171_3 -# 171| mu171_5(unknown) = UnmodeledDefinition : -# 171| r171_6(glval) = VariableAddress[w] : -# 171| m171_7(Wrapper) = InitializeParameter[w] : &:r171_6 +# 171| r171_5(glval) = VariableAddress[w] : +# 171| m171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, m171_7 +# 172| r172_3(Wrapper) = Load : &:r172_2, m171_6 # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~m171_7 +# 173| r173_4(int) = Load : &:r173_3, ~m171_6 # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -783,10 +750,9 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = UnmodeledUse : mu* -# 171| v171_10(void) = AliasedUse : m171_3 -# 171| v171_11(void) = ExitFunction : +# 171| v171_7(void) = ReturnVoid : +# 171| v171_8(void) = AliasedUse : m171_3 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -794,24 +760,22 @@ ssa.cpp: # 179| m179_2(unknown) = AliasedDefinition : # 179| m179_3(unknown) = InitializeNonLocal : # 179| m179_4(unknown) = Chi : total:m179_2, partial:m179_3 -# 179| mu179_5(unknown) = UnmodeledDefinition : -# 179| r179_6(glval) = VariableAddress[p] : -# 179| m179_7(int *) = InitializeParameter[p] : &:r179_6 -# 179| r179_8(int *) = Load : &:r179_6, m179_7 -# 179| m179_9(unknown) = InitializeIndirection[p] : &:r179_8 +# 179| r179_5(glval) = VariableAddress[p] : +# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 +# 179| r179_7(int *) = Load : &:r179_5, m179_6 +# 179| m179_8(unknown) = InitializeIndirection[p] : &:r179_7 # 180| m180_1(unknown) = InlineAsm : ~m179_4 # 180| m180_2(unknown) = Chi : total:m179_4, partial:m180_1 # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_7 -# 181| r181_4(int) = Load : &:r181_3, ~m179_9 +# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_4(int) = Load : &:r181_3, ~m179_8 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 -# 179| r179_11(glval) = VariableAddress[#return] : -# 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = UnmodeledUse : mu* -# 179| v179_14(void) = AliasedUse : ~m180_2 -# 179| v179_15(void) = ExitFunction : +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, m179_8 +# 179| r179_10(glval) = VariableAddress[#return] : +# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 +# 179| v179_12(void) = AliasedUse : ~m180_2 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -819,48 +783,46 @@ ssa.cpp: # 184| m184_2(unknown) = AliasedDefinition : # 184| m184_3(unknown) = InitializeNonLocal : # 184| m184_4(unknown) = Chi : total:m184_2, partial:m184_3 -# 184| mu184_5(unknown) = UnmodeledDefinition : -# 184| r184_6(glval) = VariableAddress[a] : -# 184| m184_7(unsigned int &) = InitializeParameter[a] : &:r184_6 -# 184| r184_8(unsigned int &) = Load : &:r184_6, m184_7 -# 184| m184_9(unknown) = InitializeIndirection[a] : &:r184_8 -# 184| m184_10(unknown) = Chi : total:m184_4, partial:m184_9 -# 184| r184_11(glval) = VariableAddress[b] : -# 184| m184_12(unsigned int &) = InitializeParameter[b] : &:r184_11 -# 184| r184_13(unsigned int &) = Load : &:r184_11, m184_12 -# 184| m184_14(unknown) = InitializeIndirection[b] : &:r184_13 -# 184| m184_15(unknown) = Chi : total:m184_10, partial:m184_14 -# 184| r184_16(glval) = VariableAddress[c] : -# 184| m184_17(unsigned int &) = InitializeParameter[c] : &:r184_16 -# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 -# 184| m184_19(unknown) = InitializeIndirection[c] : &:r184_18 -# 184| r184_20(glval) = VariableAddress[d] : -# 184| m184_21(unsigned int &) = InitializeParameter[d] : &:r184_20 -# 184| r184_22(unsigned int &) = Load : &:r184_20, m184_21 -# 184| m184_23(unknown) = InitializeIndirection[d] : &:r184_22 +# 184| r184_5(glval) = VariableAddress[a] : +# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 +# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 +# 184| m184_8(unknown) = InitializeIndirection[a] : &:r184_7 +# 184| m184_9(unknown) = Chi : total:m184_4, partial:m184_8 +# 184| r184_10(glval) = VariableAddress[b] : +# 184| m184_11(unsigned int &) = InitializeParameter[b] : &:r184_10 +# 184| r184_12(unsigned int &) = Load : &:r184_10, m184_11 +# 184| m184_13(unknown) = InitializeIndirection[b] : &:r184_12 +# 184| m184_14(unknown) = Chi : total:m184_9, partial:m184_13 +# 184| r184_15(glval) = VariableAddress[c] : +# 184| m184_16(unsigned int &) = InitializeParameter[c] : &:r184_15 +# 184| r184_17(unsigned int &) = Load : &:r184_15, m184_16 +# 184| m184_18(unknown) = InitializeIndirection[c] : &:r184_17 +# 184| r184_19(glval) = VariableAddress[d] : +# 184| m184_20(unsigned int &) = InitializeParameter[d] : &:r184_19 +# 184| r184_21(unsigned int &) = Load : &:r184_19, m184_20 +# 184| m184_22(unknown) = InitializeIndirection[d] : &:r184_21 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_7 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_12 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_11 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_17 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_19 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_16 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_18 # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_21 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_23 -# 186| m186_1(unknown) = InlineAsm : ~m184_15, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 -# 186| m186_2(unknown) = Chi : total:m184_15, partial:m186_1 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_20 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_22 +# 186| m186_1(unknown) = InlineAsm : ~m184_14, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 186| m186_2(unknown) = Chi : total:m184_14, partial:m186_1 # 192| v192_1(void) = NoOp : -# 184| v184_24(void) = ReturnIndirection[a] : &:r184_8, ~m186_2 -# 184| v184_25(void) = ReturnIndirection[b] : &:r184_13, ~m186_2 -# 184| v184_26(void) = ReturnIndirection[c] : &:r184_18, m184_19 -# 184| v184_27(void) = ReturnIndirection[d] : &:r184_22, m184_23 -# 184| v184_28(void) = ReturnVoid : -# 184| v184_29(void) = UnmodeledUse : mu* -# 184| v184_30(void) = AliasedUse : ~m186_2 -# 184| v184_31(void) = ExitFunction : +# 184| v184_23(void) = ReturnIndirection[a] : &:r184_7, ~m186_2 +# 184| v184_24(void) = ReturnIndirection[b] : &:r184_12, ~m186_2 +# 184| v184_25(void) = ReturnIndirection[c] : &:r184_17, m184_18 +# 184| v184_26(void) = ReturnIndirection[d] : &:r184_21, m184_22 +# 184| v184_27(void) = ReturnVoid : +# 184| v184_28(void) = AliasedUse : ~m186_2 +# 184| v184_29(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -868,42 +830,41 @@ ssa.cpp: # 198| m198_2(unknown) = AliasedDefinition : # 198| m198_3(unknown) = InitializeNonLocal : # 198| m198_4(unknown) = Chi : total:m198_2, partial:m198_3 -# 198| mu198_5(unknown) = UnmodeledDefinition : -# 198| r198_6(glval) = VariableAddress[str1] : -# 198| m198_7(char *) = InitializeParameter[str1] : &:r198_6 -# 198| r198_8(char *) = Load : &:r198_6, m198_7 -# 198| m198_9(unknown) = InitializeIndirection[str1] : &:r198_8 -# 198| r198_10(glval) = VariableAddress[str2] : -# 198| m198_11(char *) = InitializeParameter[str2] : &:r198_10 -# 198| r198_12(char *) = Load : &:r198_10, m198_11 -# 198| m198_13(unknown) = InitializeIndirection[str2] : &:r198_12 -# 198| r198_14(glval) = VariableAddress[x] : -# 198| m198_15(int) = InitializeParameter[x] : &:r198_14 +# 198| r198_5(glval) = VariableAddress[str1] : +# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 +# 198| r198_7(char *) = Load : &:r198_5, m198_6 +# 198| m198_8(unknown) = InitializeIndirection[str1] : &:r198_7 +# 198| r198_9(glval) = VariableAddress[str2] : +# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 +# 198| r198_11(char *) = Load : &:r198_9, m198_10 +# 198| m198_12(unknown) = InitializeIndirection[str2] : &:r198_11 +# 198| r198_13(glval) = VariableAddress[x] : +# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_7 +# 199| r199_4(char *) = Load : &:r199_3, m198_6 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_11 +# 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_8 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_12 # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_7 +# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_8 # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_15 +# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -913,13 +874,12 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_16(void) = ReturnIndirection[str1] : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 -# 198| r198_18(glval) = VariableAddress[#return] : -# 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = UnmodeledUse : mu* -# 198| v198_21(void) = AliasedUse : m198_3 -# 198| v198_22(void) = ExitFunction : +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, m198_8 +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, m198_12 +# 198| r198_17(glval) = VariableAddress[#return] : +# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 +# 198| v198_19(void) = AliasedUse : m198_3 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -927,13 +887,12 @@ ssa.cpp: # 207| m207_2(unknown) = AliasedDefinition : # 207| m207_3(unknown) = InitializeNonLocal : # 207| m207_4(unknown) = Chi : total:m207_2, partial:m207_3 -# 207| mu207_5(unknown) = UnmodeledDefinition : -# 207| r207_6(glval) = VariableAddress[x] : -# 207| m207_7(int) = InitializeParameter[x] : &:r207_6 -# 207| m207_8(unknown) = Chi : total:m207_4, partial:m207_7 +# 207| r207_5(glval) = VariableAddress[x] : +# 207| m207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| m207_7(unknown) = Chi : total:m207_4, partial:m207_6 # 208| r208_1(glval) = VariableAddress[y] : # 208| m208_2(int) = Uninitialized[y] : &:r208_1 -# 208| m208_3(unknown) = Chi : total:m207_8, partial:m208_2 +# 208| m208_3(unknown) = Chi : total:m207_7, partial:m208_2 # 209| r209_1(glval) = FunctionAddress[memcpy] : # 209| r209_2(glval) = VariableAddress[y] : # 209| r209_3(int *) = CopyValue : r209_2 @@ -943,18 +902,17 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_7 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_6 # 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 209| m209_12(unknown) = Chi : total:m208_3, partial:m209_11 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, ~m209_12 # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_9(glval) = VariableAddress[#return] : -# 207| v207_10(void) = ReturnValue : &:r207_9, m210_4 -# 207| v207_11(void) = UnmodeledUse : mu* -# 207| v207_12(void) = AliasedUse : m207_3 -# 207| v207_13(void) = ExitFunction : +# 207| r207_8(glval) = VariableAddress[#return] : +# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 +# 207| v207_10(void) = AliasedUse : m207_3 +# 207| v207_11(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -962,7 +920,6 @@ ssa.cpp: # 213| m213_2(unknown) = AliasedDefinition : # 213| m213_3(unknown) = InitializeNonLocal : # 213| m213_4(unknown) = Chi : total:m213_2, partial:m213_3 -# 213| mu213_5(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m213_3 @@ -1020,10 +977,9 @@ ssa.cpp: # 221| m221_11(unknown[2]) = Store : &:r221_9, r221_10 # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : -# 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = UnmodeledUse : mu* -# 213| v213_8(void) = AliasedUse : m213_3 -# 213| v213_9(void) = ExitFunction : +# 213| v213_5(void) = ReturnVoid : +# 213| v213_6(void) = AliasedUse : m213_3 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1031,7 +987,6 @@ ssa.cpp: # 226| m226_2(unknown) = AliasedDefinition : # 226| m226_3(unknown) = InitializeNonLocal : # 226| m226_4(unknown) = Chi : total:m226_2, partial:m226_3 -# 226| mu226_5(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| m227_3(unknown) = ^CallSideEffect : ~m226_4 @@ -1047,41 +1002,44 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m226_3 # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_6(glval) = VariableAddress[#return] : -# 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = UnmodeledUse : mu* -# 226| v226_9(void) = AliasedUse : ~m227_4 -# 226| v226_10(void) = ExitFunction : +# 226| r226_5(glval) = VariableAddress[#return] : +# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 +# 226| v226_7(void) = AliasedUse : ~m227_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| m235_2(unknown) = AliasedDefinition : -# 235| m235_3(unknown) = InitializeNonLocal : -# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| mu235_5(unknown) = UnmodeledDefinition : -# 235| r235_6(glval) = InitializeThis : -# 235| r235_7(glval) = VariableAddress[x] : -# 235| m235_8(int) = InitializeParameter[x] : &:r235_7 -# 235| v235_9(void) = NoOp : -# 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : m235_3 -# 235| v235_13(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| m235_2(unknown) = AliasedDefinition : +# 235| m235_3(unknown) = InitializeNonLocal : +# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 +# 235| r235_5(glval) = VariableAddress[#this] : +# 235| m235_6(glval) = InitializeParameter[#this] : &:r235_5 +# 235| r235_7(glval) = Load : &:r235_5, m235_6 +# 235| m235_8(Constructible) = InitializeIndirection[#this] : &:r235_7 +# 235| r235_9(glval) = VariableAddress[x] : +# 235| m235_10(int) = InitializeParameter[x] : &:r235_9 +# 235| v235_11(void) = NoOp : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| mu236_5(unknown) = UnmodeledDefinition : -# 236| r236_6(glval) = InitializeThis : -# 236| v236_7(void) = NoOp : -# 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = UnmodeledUse : mu* -# 236| v236_10(void) = AliasedUse : m236_3 -# 236| v236_11(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = VariableAddress[#this] : +# 236| m236_6(glval) = InitializeParameter[#this] : &:r236_5 +# 236| r236_7(glval) = Load : &:r236_5, m236_6 +# 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 +# 236| v236_9(void) = NoOp : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1089,7 +1047,6 @@ ssa.cpp: # 239| m239_2(unknown) = AliasedDefinition : # 239| m239_3(unknown) = InitializeNonLocal : # 239| m239_4(unknown) = Chi : total:m239_2, partial:m239_3 -# 239| mu239_5(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| m240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1133,10 +1090,9 @@ ssa.cpp: # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : -# 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = UnmodeledUse : mu* -# 239| v239_8(void) = AliasedUse : ~m244_5 -# 239| v239_9(void) = ExitFunction : +# 239| v239_5(void) = ReturnVoid : +# 239| v239_6(void) = AliasedUse : ~m244_5 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1144,31 +1100,30 @@ ssa.cpp: # 247| m247_2(unknown) = AliasedDefinition : # 247| m247_3(unknown) = InitializeNonLocal : # 247| m247_4(unknown) = Chi : total:m247_2, partial:m247_3 -# 247| mu247_5(unknown) = UnmodeledDefinition : -# 247| r247_6(glval) = VariableAddress[src] : -# 247| m247_7(char *) = InitializeParameter[src] : &:r247_6 -# 247| r247_8(char *) = Load : &:r247_6, m247_7 -# 247| m247_9(unknown) = InitializeIndirection[src] : &:r247_8 -# 247| m247_10(unknown) = Chi : total:m247_4, partial:m247_9 -# 247| r247_11(glval) = VariableAddress[size] : -# 247| m247_12(int) = InitializeParameter[size] : &:r247_11 +# 247| r247_5(glval) = VariableAddress[src] : +# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 +# 247| r247_7(char *) = Load : &:r247_5, m247_6 +# 247| m247_8(unknown) = InitializeIndirection[src] : &:r247_7 +# 247| m247_9(unknown) = Chi : total:m247_4, partial:m247_8 +# 247| r247_10(glval) = VariableAddress[size] : +# 247| m247_11(int) = InitializeParameter[size] : &:r247_10 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_12 +# 248| r248_4(int) = Load : &:r248_3, m247_11 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| m248_9(unknown) = ^CallSideEffect : ~m247_10 -# 248| m248_10(unknown) = Chi : total:m247_10, partial:m248_9 +# 248| m248_9(unknown) = ^CallSideEffect : ~m247_9 +# 248| m248_10(unknown) = Chi : total:m247_9, partial:m248_9 # 248| m248_11(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| m248_12(unknown) = Chi : total:m248_10, partial:m248_11 # 248| r248_13(char *) = Convert : r248_8 # 248| m248_14(char *) = Store : &:r248_1, r248_13 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_7 +# 249| r249_3(char *) = Load : &:r249_2, m247_6 # 249| r249_4(glval) = CopyValue : r249_3 # 249| m249_5(char) = Store : &:r249_4, r249_1 # 249| m249_6(unknown) = Chi : total:m248_12, partial:m249_5 @@ -1177,10 +1132,10 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_14 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_7 +# 250| r250_6(char *) = Load : &:r250_5, m247_6 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_12 +# 250| r250_9(int) = Load : &:r250_8, m247_11 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m249_6 # 250| m250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1189,12 +1144,11 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_14 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_13(void) = ReturnIndirection[src] : &:r247_8, ~m250_13 -# 247| r247_14(glval) = VariableAddress[#return] : -# 247| v247_15(void) = ReturnValue : &:r247_14, m251_4 -# 247| v247_16(void) = UnmodeledUse : mu* -# 247| v247_17(void) = AliasedUse : ~m250_13 -# 247| v247_18(void) = ExitFunction : +# 247| v247_12(void) = ReturnIndirection[src] : &:r247_7, ~m250_13 +# 247| r247_13(glval) = VariableAddress[#return] : +# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 +# 247| v247_15(void) = AliasedUse : ~m250_13 +# 247| v247_16(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1202,11 +1156,10 @@ ssa.cpp: # 254| m254_2(unknown) = AliasedDefinition : # 254| m254_3(unknown) = InitializeNonLocal : # 254| m254_4(unknown) = Chi : total:m254_2, partial:m254_3 -# 254| mu254_5(unknown) = UnmodeledDefinition : -# 254| r254_6(glval) = VariableAddress[b] : -# 254| m254_7(bool) = InitializeParameter[b] : &:r254_6 +# 254| r254_5(glval) = VariableAddress[b] : +# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_7 +# 255| r255_2(bool) = Load : &:r255_1, m254_6 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1238,11 +1191,10 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m254_3 # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_8(glval) = VariableAddress[#return] : -# 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = UnmodeledUse : mu* -# 254| v254_11(void) = AliasedUse : ~m262_1 -# 254| v254_12(void) = ExitFunction : +# 254| r254_7(glval) = VariableAddress[#return] : +# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 +# 254| v254_9(void) = AliasedUse : ~m262_1 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1250,21 +1202,20 @@ ssa.cpp: # 268| m268_2(unknown) = AliasedDefinition : # 268| m268_3(unknown) = InitializeNonLocal : # 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 -# 268| mu268_5(unknown) = UnmodeledDefinition : -# 268| r268_6(glval) = VariableAddress[s] : -# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 -# 268| r268_8(void *) = Load : &:r268_6, m268_7 -# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 -# 268| m268_10(unknown) = Chi : total:m268_4, partial:m268_9 -# 268| r268_11(glval) = VariableAddress[size] : -# 268| m268_12(int) = InitializeParameter[size] : &:r268_11 +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| m268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| m268_9(unknown) = Chi : total:m268_4, partial:m268_8 +# 268| r268_10(glval) = VariableAddress[size] : +# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_12 +# 269| r269_4(int) = Load : &:r269_3, m268_11 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| m269_6(unknown) = ^CallSideEffect : ~m268_10 -# 269| m269_7(unknown) = Chi : total:m268_10, partial:m269_6 +# 269| m269_6(unknown) = ^CallSideEffect : ~m268_9 +# 269| m269_7(unknown) = Chi : total:m268_9, partial:m269_6 # 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_9(unknown) = Chi : total:m269_7, partial:m269_8 # 269| m269_10(void *) = Store : &:r269_1, r269_5 @@ -1272,9 +1223,9 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_10 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_5(void *) = Load : &:r270_4, m268_6 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_12 +# 270| r270_7(int) = Load : &:r270_6, m268_11 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 # 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m269_7 # 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 @@ -1283,12 +1234,11 @@ ssa.cpp: # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_10 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_13(void) = ReturnIndirection[s] : &:r268_8, ~m270_11 -# 268| r268_14(glval) = VariableAddress[#return] : -# 268| v268_15(void) = ReturnValue : &:r268_14, m271_4 -# 268| v268_16(void) = UnmodeledUse : mu* -# 268| v268_17(void) = AliasedUse : ~m270_11 -# 268| v268_18(void) = ExitFunction : +# 268| v268_12(void) = ReturnIndirection[s] : &:r268_7, ~m270_11 +# 268| r268_13(glval) = VariableAddress[#return] : +# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 +# 268| v268_15(void) = AliasedUse : ~m270_11 +# 268| v268_16(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1296,13 +1246,12 @@ ssa.cpp: # 275| m275_2(unknown) = AliasedDefinition : # 275| m275_3(unknown) = InitializeNonLocal : # 275| m275_4(unknown) = Chi : total:m275_2, partial:m275_3 -# 275| mu275_5(unknown) = UnmodeledDefinition : -# 275| r275_6(glval) = VariableAddress[c] : -# 275| m275_7(bool) = InitializeParameter[c] : &:r275_6 -# 275| r275_8(glval) = VariableAddress[p] : -# 275| m275_9(Point) = InitializeParameter[p] : &:r275_8 -# 275| r275_10(glval) = VariableAddress[x1] : -# 275| m275_11(int) = InitializeParameter[x1] : &:r275_10 +# 275| r275_5(glval) = VariableAddress[c] : +# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 +# 275| r275_7(glval) = VariableAddress[p] : +# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 +# 275| r275_9(glval) = VariableAddress[x1] : +# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 # 276| r276_1(glval) = VariableAddress[a] : # 276| m276_2(Point) = Uninitialized[a] : &:r276_1 # 276| m276_3(unknown) = Chi : total:m275_4, partial:m276_2 @@ -1320,14 +1269,14 @@ ssa.cpp: # 277| m277_4(Point *) = Store : &:r277_3, r277_2 # 277| m277_5(unknown) = Chi : total:m276_11, partial:m277_4 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_7 +# 278| r278_2(bool) = Load : &:r278_1, m275_6 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_11 +# 279| r279_2(int) = Load : &:r279_1, m275_10 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| m279_5(int) = Store : &:r279_4, r279_2 @@ -1343,59 +1292,64 @@ ssa.cpp: # 281| r281_6(int) = Load : &:r281_5, m281_1 # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : -# 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = UnmodeledUse : mu* -# 275| v275_14(void) = AliasedUse : ~m281_2 -# 275| v275_15(void) = ExitFunction : +# 275| v275_11(void) = ReturnVoid : +# 275| v275_12(void) = AliasedUse : ~m281_2 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| m286_2(unknown) = AliasedDefinition : -# 286| m286_3(unknown) = InitializeNonLocal : -# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| mu286_5(unknown) = UnmodeledDefinition : -# 286| r286_6(glval) = InitializeThis : -# 286| r286_7(glval) = VariableAddress[x] : -# 286| m286_8(int) = InitializeParameter[x] : &:r286_7 -# 286| v286_9(void) = NoOp : -# 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = UnmodeledUse : mu* -# 286| v286_12(void) = AliasedUse : m286_3 -# 286| v286_13(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| m286_2(unknown) = AliasedDefinition : +# 286| m286_3(unknown) = InitializeNonLocal : +# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 +# 286| r286_5(glval) = VariableAddress[#this] : +# 286| m286_6(glval) = InitializeParameter[#this] : &:r286_5 +# 286| r286_7(glval) = Load : &:r286_5, m286_6 +# 286| m286_8(A) = InitializeIndirection[#this] : &:r286_7 +# 286| r286_9(glval) = VariableAddress[x] : +# 286| m286_10(int) = InitializeParameter[x] : &:r286_9 +# 286| v286_11(void) = NoOp : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| m287_2(unknown) = AliasedDefinition : -# 287| m287_3(unknown) = InitializeNonLocal : -# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| mu287_5(unknown) = UnmodeledDefinition : -# 287| r287_6(glval) = InitializeThis : -# 287| r287_7(glval) = VariableAddress[p#0] : -# 287| m287_8(A *) = InitializeParameter[p#0] : &:r287_7 -# 287| r287_9(A *) = Load : &:r287_7, m287_8 -# 287| m287_10(unknown) = InitializeIndirection[p#0] : &:r287_9 -# 287| v287_11(void) = NoOp : -# 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 -# 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = UnmodeledUse : mu* -# 287| v287_15(void) = AliasedUse : m287_3 -# 287| v287_16(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| m287_2(unknown) = AliasedDefinition : +# 287| m287_3(unknown) = InitializeNonLocal : +# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 +# 287| r287_5(glval) = VariableAddress[#this] : +# 287| m287_6(glval) = InitializeParameter[#this] : &:r287_5 +# 287| r287_7(glval) = Load : &:r287_5, m287_6 +# 287| m287_8(A) = InitializeIndirection[#this] : &:r287_7 +# 287| r287_9(glval) = VariableAddress[p#0] : +# 287| m287_10(A *) = InitializeParameter[p#0] : &:r287_9 +# 287| r287_11(A *) = Load : &:r287_9, m287_10 +# 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 +# 287| v287_13(void) = NoOp : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| mu288_5(unknown) = UnmodeledDefinition : -# 288| r288_6(glval) = InitializeThis : -# 288| v288_7(void) = NoOp : -# 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = UnmodeledUse : mu* -# 288| v288_10(void) = AliasedUse : m288_3 -# 288| v288_11(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = VariableAddress[#this] : +# 288| m288_6(glval) = InitializeParameter[#this] : &:r288_5 +# 288| r288_7(glval) = Load : &:r288_5, m288_6 +# 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 +# 288| v288_9(void) = NoOp : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1403,9 +1357,8 @@ ssa.cpp: # 291| m291_2(unknown) = AliasedDefinition : # 291| m291_3(unknown) = InitializeNonLocal : # 291| m291_4(unknown) = Chi : total:m291_2, partial:m291_3 -# 291| mu291_5(unknown) = UnmodeledDefinition : -# 291| r291_6(glval) = VariableAddress[x] : -# 291| m291_7(int) = InitializeParameter[x] : &:r291_6 +# 291| r291_5(glval) = VariableAddress[x] : +# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1442,7 +1395,7 @@ ssa.cpp: # 294| r294_16(A *) = Convert : r294_12 # 294| r294_17(glval) = FunctionAddress[A] : # 294| r294_18(glval) = VariableAddress[x] : -# 294| r294_19(int) = Load : &:r294_18, m291_7 +# 294| r294_19(int) = Load : &:r294_18, m291_6 # 294| v294_20(void) = Call : func:r294_17, this:r294_16, 0:r294_19 # 294| m294_21(unknown) = ^CallSideEffect : ~m294_14 # 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21 @@ -1478,11 +1431,10 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_9 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_8(glval) = VariableAddress[#return] : -# 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = UnmodeledUse : mu* -# 291| v291_11(void) = AliasedUse : ~m295_12 -# 291| v291_12(void) = ExitFunction : +# 291| r291_7(glval) = VariableAddress[#return] : +# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 +# 291| v291_9(void) = AliasedUse : ~m295_12 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1490,30 +1442,29 @@ ssa.cpp: # 301| m301_2(unknown) = AliasedDefinition : # 301| m301_3(unknown) = InitializeNonLocal : # 301| m301_4(unknown) = Chi : total:m301_2, partial:m301_3 -# 301| mu301_5(unknown) = UnmodeledDefinition : -# 301| r301_6(glval) = VariableAddress[argc] : -# 301| m301_7(int) = InitializeParameter[argc] : &:r301_6 -# 301| r301_8(glval) = VariableAddress[argv] : -# 301| m301_9(char **) = InitializeParameter[argv] : &:r301_8 -# 301| r301_10(char **) = Load : &:r301_8, m301_9 -# 301| m301_11(unknown) = InitializeIndirection[argv] : &:r301_10 -# 301| m301_12(unknown) = Chi : total:m301_4, partial:m301_11 +# 301| r301_5(glval) = VariableAddress[argc] : +# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 +# 301| r301_7(glval) = VariableAddress[argv] : +# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 +# 301| r301_9(char **) = Load : &:r301_7, m301_8 +# 301| m301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| m301_11(unknown) = Chi : total:m301_4, partial:m301_10 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_3(int) = Load : &:r302_2, m301_6 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| m302_7(unknown) = ^CallSideEffect : ~m301_12 -# 302| m302_8(unknown) = Chi : total:m301_12, partial:m302_7 +# 302| m302_7(unknown) = ^CallSideEffect : ~m301_11 +# 302| m302_8(unknown) = Chi : total:m301_11, partial:m302_7 # 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m302_8 # 302| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 302| m302_11(unknown) = Chi : total:m302_8, partial:m302_10 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_7 +# 303| r303_3(int) = Load : &:r303_2, m301_6 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| m303_7(unknown) = ^CallSideEffect : ~m302_11 # 303| m303_8(unknown) = Chi : total:m302_11, partial:m303_7 @@ -1522,14 +1473,38 @@ ssa.cpp: # 303| m303_11(unknown) = Chi : total:m303_8, partial:m303_10 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_9 +# 304| r304_3(char **) = Load : &:r304_2, m301_8 # 304| r304_4(char *) = Load : &:r304_3, ~m303_11 # 304| r304_5(char) = Load : &:r304_4, ~m303_11 # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_13(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11 -# 301| r301_14(glval) = VariableAddress[#return] : -# 301| v301_15(void) = ReturnValue : &:r301_14, m304_7 -# 301| v301_16(void) = UnmodeledUse : mu* -# 301| v301_17(void) = AliasedUse : ~m303_11 -# 301| v301_18(void) = ExitFunction : +# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_9, ~m303_11 +# 301| r301_13(glval) = VariableAddress[#return] : +# 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 +# 301| v301_15(void) = AliasedUse : ~m303_11 +# 301| v301_16(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| m310_2(unknown) = AliasedDefinition : +# 310| m310_3(unknown) = InitializeNonLocal : +# 310| m310_4(unknown) = Chi : total:m310_2, partial:m310_3 +# 310| r310_5(glval) = VariableAddress[#this] : +# 310| m310_6(glval) = InitializeParameter[#this] : &:r310_5 +# 310| r310_7(glval) = Load : &:r310_5, m310_6 +# 310| m310_8(ThisAliasTest) = InitializeIndirection[#this] : &:r310_7 +# 310| r310_9(glval) = VariableAddress[arg] : +# 310| m310_10(int) = InitializeParameter[arg] : &:r310_9 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_10 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_6 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| m311_6(int) = Store : &:r311_5, r311_2 +# 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 +# 312| v312_1(void) = NoOp : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index 01af278d8d9..ef07fde174d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -5,56 +5,55 @@ ssa.cpp: # 13| m13_2(unknown) = AliasedDefinition : # 13| m13_3(unknown) = InitializeNonLocal : # 13| m13_4(unknown) = Chi : total:m13_2, partial:m13_3 -# 13| mu13_5(unknown) = UnmodeledDefinition : -# 13| r13_6(glval) = VariableAddress[p] : -# 13| m13_7(Point *) = InitializeParameter[p] : &:r13_6 -# 13| r13_8(Point *) = Load : &:r13_6, m13_7 -# 13| m13_9(unknown) = InitializeIndirection[p] : &:r13_8 -# 13| r13_10(glval) = VariableAddress[which1] : -# 13| m13_11(bool) = InitializeParameter[which1] : &:r13_10 -# 13| r13_12(glval) = VariableAddress[which2] : -# 13| m13_13(bool) = InitializeParameter[which2] : &:r13_12 +# 13| r13_5(glval) = VariableAddress[p] : +# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 +# 13| r13_7(Point *) = Load : &:r13_5, m13_6 +# 13| m13_8(unknown) = InitializeIndirection[p] : &:r13_7 +# 13| r13_9(glval) = VariableAddress[which1] : +# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 +# 13| r13_11(glval) = VariableAddress[which2] : +# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_11 +# 14| r14_2(bool) = Load : &:r14_1, m13_10 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_7 +# 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~m13_9 +# 15| r15_4(int) = Load : &:r15_3, ~m13_8 # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| m15_7(int) = Store : &:r15_3, r15_6 -# 15| m15_8(unknown) = Chi : total:m13_9, partial:m15_7 +# 15| m15_8(unknown) = Chi : total:m13_8, partial:m15_7 #-----| Goto -> Block 3 # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_7 +# 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~m13_9 +# 18| r18_4(int) = Load : &:r18_3, ~m13_8 # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| m18_7(int) = Store : &:r18_3, r18_6 -# 18| m18_8(unknown) = Chi : total:m13_9, partial:m18_7 +# 18| m18_8(unknown) = Chi : total:m13_8, partial:m18_7 #-----| Goto -> Block 3 # 21| Block 3 -# 21| m21_1(int) = Phi : from 1:~m13_9, from 2:m18_7 -# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_9 +# 21| m21_1(int) = Phi : from 1:~m13_8, from 2:m18_7 +# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_8 # 21| m21_3(unknown) = Phi : from 1:m15_8, from 2:m18_8 # 21| r21_4(glval) = VariableAddress[which2] : -# 21| r21_5(bool) = Load : &:r21_4, m13_13 +# 21| r21_5(bool) = Load : &:r21_4, m13_12 # 21| v21_6(void) = ConditionalBranch : r21_5 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_7 +# 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, m21_2 # 22| r22_5(int) = Constant[1] : @@ -65,7 +64,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_7 +# 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, m21_1 # 25| r25_5(int) = Constant[1] : @@ -80,21 +79,20 @@ ssa.cpp: # 28| m28_3(unknown) = Phi : from 4:m22_8, from 5:m25_8 # 28| r28_4(glval) = VariableAddress[#return] : # 28| r28_5(glval) = VariableAddress[p] : -# 28| r28_6(Point *) = Load : &:r28_5, m13_7 +# 28| r28_6(Point *) = Load : &:r28_5, m13_6 # 28| r28_7(glval) = FieldAddress[x] : r28_6 # 28| r28_8(int) = Load : &:r28_7, m28_2 # 28| r28_9(glval) = VariableAddress[p] : -# 28| r28_10(Point *) = Load : &:r28_9, m13_7 +# 28| r28_10(Point *) = Load : &:r28_9, m13_6 # 28| r28_11(glval) = FieldAddress[y] : r28_10 # 28| r28_12(int) = Load : &:r28_11, m28_1 # 28| r28_13(int) = Add : r28_8, r28_12 # 28| m28_14(int) = Store : &:r28_4, r28_13 -# 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 -# 13| r13_15(glval) = VariableAddress[#return] : -# 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = UnmodeledUse : mu* -# 13| v13_18(void) = AliasedUse : m13_3 -# 13| v13_19(void) = ExitFunction : +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, m28_3 +# 13| r13_14(glval) = VariableAddress[#return] : +# 13| v13_15(void) = ReturnValue : &:r13_14, m28_14 +# 13| v13_16(void) = AliasedUse : m13_3 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -102,17 +100,15 @@ ssa.cpp: # 31| m31_2(unknown) = AliasedDefinition : # 31| m31_3(unknown) = InitializeNonLocal : # 31| m31_4(unknown) = Chi : total:m31_2, partial:m31_3 -# 31| mu31_5(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_6(glval) = VariableAddress[#return] : -# 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = UnmodeledUse : mu* -# 31| v31_9(void) = AliasedUse : m31_3 -# 31| v31_10(void) = ExitFunction : +# 31| r31_5(glval) = VariableAddress[#return] : +# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 +# 31| v31_7(void) = AliasedUse : m31_3 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -120,9 +116,8 @@ ssa.cpp: # 38| m38_2(unknown) = AliasedDefinition : # 38| m38_3(unknown) = InitializeNonLocal : # 38| m38_4(unknown) = Chi : total:m38_2, partial:m38_3 -# 38| mu38_5(unknown) = UnmodeledDefinition : -# 38| r38_6(glval) = VariableAddress[b] : -# 38| m38_7(bool) = InitializeParameter[b] : &:r38_6 +# 38| r38_5(glval) = VariableAddress[b] : +# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -130,18 +125,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_7 +# 41| r41_2(bool) = Load : &:r41_1, m38_6 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 4 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 -# 38| r38_9(glval) = VariableAddress[#return] : -# 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = UnmodeledUse : mu* -# 38| v38_12(void) = AliasedUse : m38_3 -# 38| v38_13(void) = ExitFunction : +# 38| m38_7(int) = Phi : from 3:m46_3, from 5:m51_3 +# 38| r38_8(glval) = VariableAddress[#return] : +# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 +# 38| v38_10(void) = AliasedUse : m38_3 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,25 +170,24 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_14(void) = Unreached : +# 38| v38_12(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| m59_2(unknown) = AliasedDefinition : -# 59| m59_3(unknown) = InitializeNonLocal : -# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 -# 59| mu59_5(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| m59_2(unknown) = AliasedDefinition : +# 59| m59_3(unknown) = InitializeNonLocal : +# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -203,14 +196,13 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_6(glval) = VariableAddress[#return] : -# 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = UnmodeledUse : mu* -# 59| v59_9(void) = AliasedUse : m59_3 -# 59| v59_10(void) = ExitFunction : +# 59| r59_5(glval) = VariableAddress[#return] : +# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 +# 59| v59_7(void) = AliasedUse : m59_3 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_11(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -218,18 +210,17 @@ ssa.cpp: # 68| m68_2(unknown) = AliasedDefinition : # 68| m68_3(unknown) = InitializeNonLocal : # 68| m68_4(unknown) = Chi : total:m68_2, partial:m68_3 -# 68| mu68_5(unknown) = UnmodeledDefinition : -# 68| r68_6(glval) = VariableAddress[n] : -# 68| m68_7(int) = InitializeParameter[n] : &:r68_6 -# 68| r68_8(glval) = VariableAddress[p] : -# 68| m68_9(char *) = InitializeParameter[p] : &:r68_8 -# 68| r68_10(char *) = Load : &:r68_8, m68_9 -# 68| m68_11(unknown) = InitializeIndirection[p] : &:r68_10 +# 68| r68_5(glval) = VariableAddress[n] : +# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 +# 68| r68_7(glval) = VariableAddress[p] : +# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 +# 68| r68_9(char *) = Load : &:r68_7, m68_8 +# 68| m68_10(unknown) = InitializeIndirection[p] : &:r68_9 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_9, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_7, from 2:m69_8 +# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_8 # 69| m69_3(unknown) = Phi : from 0:~m68_4, from 2:~m70_10 # 69| r69_4(glval) = VariableAddress[n] : # 69| r69_5(int) = Load : &:r69_4, m69_2 @@ -258,11 +249,10 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 -# 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = UnmodeledUse : mu* -# 68| v68_15(void) = AliasedUse : ~m69_3 -# 68| v68_16(void) = ExitFunction : +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10 +# 68| v68_12(void) = ReturnVoid : +# 68| v68_13(void) = AliasedUse : ~m69_3 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -270,9 +260,8 @@ ssa.cpp: # 75| m75_2(unknown) = AliasedDefinition : # 75| m75_3(unknown) = InitializeNonLocal : # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| r75_6(glval) = VariableAddress[b] : -# 75| m75_7(bool) = InitializeParameter[b] : &:r75_6 +# 75| r75_5(glval) = VariableAddress[b] : +# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -283,7 +272,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_7 +# 79| r79_2(bool) = Load : &:r79_1, m75_6 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -319,10 +308,9 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = UnmodeledUse : mu* -# 75| v75_10(void) = AliasedUse : m75_3 -# 75| v75_11(void) = ExitFunction : +# 75| v75_7(void) = ReturnVoid : +# 75| v75_8(void) = AliasedUse : m75_3 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -330,18 +318,16 @@ ssa.cpp: # 91| m91_2(unknown) = AliasedDefinition : # 91| m91_3(unknown) = InitializeNonLocal : # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| r91_6(glval) = VariableAddress[a] : -# 91| m91_7(Point) = InitializeParameter[a] : &:r91_6 +# 91| r91_5(glval) = VariableAddress[a] : +# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_7 +# 92| r92_3(Point) = Load : &:r92_2, m91_6 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = UnmodeledUse : mu* -# 91| v91_10(void) = AliasedUse : m91_3 -# 91| v91_11(void) = ExitFunction : +# 91| v91_7(void) = ReturnVoid : +# 91| v91_8(void) = AliasedUse : m91_3 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -349,12 +335,11 @@ ssa.cpp: # 95| m95_2(unknown) = AliasedDefinition : # 95| m95_3(unknown) = InitializeNonLocal : # 95| m95_4(unknown) = Chi : total:m95_2, partial:m95_3 -# 95| mu95_5(unknown) = UnmodeledDefinition : -# 95| r95_6(glval) = VariableAddress[a] : -# 95| m95_7(Point) = InitializeParameter[a] : &:r95_6 +# 95| r95_5(glval) = VariableAddress[a] : +# 95| m95_6(Point) = InitializeParameter[a] : &:r95_5 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, m95_7 +# 96| r96_3(Point) = Load : &:r96_2, m95_6 # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : @@ -363,14 +348,13 @@ ssa.cpp: # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 # 97| m97_6(unknown) = ^CallSideEffect : ~m95_4 # 97| m97_7(unknown) = Chi : total:m95_4, partial:m97_6 -# 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m95_7 +# 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m95_6 # 97| m97_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 -# 97| m97_10(Point) = Chi : total:m95_7, partial:m97_9 +# 97| m97_10(Point) = Chi : total:m95_6, partial:m97_9 # 98| v98_1(void) = NoOp : -# 95| v95_8(void) = ReturnVoid : -# 95| v95_9(void) = UnmodeledUse : mu* -# 95| v95_10(void) = AliasedUse : ~m97_7 -# 95| v95_11(void) = ExitFunction : +# 95| v95_7(void) = ReturnVoid : +# 95| v95_8(void) = AliasedUse : ~m97_7 +# 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -378,24 +362,22 @@ ssa.cpp: # 100| m100_2(unknown) = AliasedDefinition : # 100| m100_3(unknown) = InitializeNonLocal : # 100| m100_4(unknown) = Chi : total:m100_2, partial:m100_3 -# 100| mu100_5(unknown) = UnmodeledDefinition : -# 100| r100_6(glval) = VariableAddress[a] : -# 100| m100_7(Point) = InitializeParameter[a] : &:r100_6 +# 100| r100_5(glval) = VariableAddress[a] : +# 100| m100_6(Point) = InitializeParameter[a] : &:r100_5 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~m100_7 +# 101| r101_4(int) = Load : &:r101_3, ~m100_6 # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~m100_7 +# 102| r102_4(int) = Load : &:r102_3, ~m100_6 # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = UnmodeledUse : mu* -# 100| v100_10(void) = AliasedUse : m100_3 -# 100| v100_11(void) = ExitFunction : +# 100| v100_7(void) = ReturnVoid : +# 100| v100_8(void) = AliasedUse : m100_3 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -403,18 +385,17 @@ ssa.cpp: # 105| m105_2(unknown) = AliasedDefinition : # 105| m105_3(unknown) = InitializeNonLocal : # 105| m105_4(unknown) = Chi : total:m105_2, partial:m105_3 -# 105| mu105_5(unknown) = UnmodeledDefinition : -# 105| r105_6(glval) = VariableAddress[a] : -# 105| m105_7(Point) = InitializeParameter[a] : &:r105_6 +# 105| r105_5(glval) = VariableAddress[a] : +# 105| m105_6(Point) = InitializeParameter[a] : &:r105_5 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~m105_7 +# 106| r106_4(int) = Load : &:r106_3, ~m105_6 # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~m105_7 +# 107| r107_4(int) = Load : &:r107_3, ~m105_6 # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : @@ -423,14 +404,13 @@ ssa.cpp: # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 # 108| m108_6(unknown) = ^CallSideEffect : ~m105_4 # 108| m108_7(unknown) = Chi : total:m105_4, partial:m108_6 -# 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m105_7 +# 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m105_6 # 108| m108_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 -# 108| m108_10(Point) = Chi : total:m105_7, partial:m108_9 +# 108| m108_10(Point) = Chi : total:m105_6, partial:m108_9 # 109| v109_1(void) = NoOp : -# 105| v105_8(void) = ReturnVoid : -# 105| v105_9(void) = UnmodeledUse : mu* -# 105| v105_10(void) = AliasedUse : ~m108_7 -# 105| v105_11(void) = ExitFunction : +# 105| v105_7(void) = ReturnVoid : +# 105| v105_8(void) = AliasedUse : ~m108_7 +# 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -438,21 +418,20 @@ ssa.cpp: # 111| m111_2(unknown) = AliasedDefinition : # 111| m111_3(unknown) = InitializeNonLocal : # 111| m111_4(unknown) = Chi : total:m111_2, partial:m111_3 -# 111| mu111_5(unknown) = UnmodeledDefinition : -# 111| r111_6(glval) = VariableAddress[x] : -# 111| m111_7(int) = InitializeParameter[x] : &:r111_6 -# 111| r111_8(glval) = VariableAddress[y] : -# 111| m111_9(int) = InitializeParameter[y] : &:r111_8 +# 111| r111_5(glval) = VariableAddress[x] : +# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 +# 111| r111_7(glval) = VariableAddress[y] : +# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 # 112| r112_1(glval) = VariableAddress[a] : # 112| m112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_7 +# 112| r112_5(int) = Load : &:r112_4, m111_6 # 112| m112_6(int) = Store : &:r112_3, r112_5 # 112| m112_7(Point) = Chi : total:m112_2, partial:m112_6 # 112| r112_8(glval) = FieldAddress[y] : r112_1 # 112| r112_9(glval) = VariableAddress[y] : -# 112| r112_10(int) = Load : &:r112_9, m111_9 +# 112| r112_10(int) = Load : &:r112_9, m111_8 # 112| m112_11(int) = Store : &:r112_8, r112_10 # 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11 # 113| r113_1(glval) = VariableAddress[b] : @@ -460,10 +439,9 @@ ssa.cpp: # 113| r113_3(Point) = Load : &:r113_2, m112_12 # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = UnmodeledUse : mu* -# 111| v111_12(void) = AliasedUse : m111_3 -# 111| v111_13(void) = ExitFunction : +# 111| v111_9(void) = ReturnVoid : +# 111| v111_10(void) = AliasedUse : m111_3 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -471,21 +449,20 @@ ssa.cpp: # 116| m116_2(unknown) = AliasedDefinition : # 116| m116_3(unknown) = InitializeNonLocal : # 116| m116_4(unknown) = Chi : total:m116_2, partial:m116_3 -# 116| mu116_5(unknown) = UnmodeledDefinition : -# 116| r116_6(glval) = VariableAddress[x] : -# 116| m116_7(int) = InitializeParameter[x] : &:r116_6 -# 116| r116_8(glval) = VariableAddress[y] : -# 116| m116_9(int) = InitializeParameter[y] : &:r116_8 +# 116| r116_5(glval) = VariableAddress[x] : +# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 +# 116| r116_7(glval) = VariableAddress[y] : +# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 # 117| r117_1(glval) = VariableAddress[a] : # 117| m117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_7 +# 117| r117_5(int) = Load : &:r117_4, m116_6 # 117| m117_6(int) = Store : &:r117_3, r117_5 # 117| m117_7(Point) = Chi : total:m117_2, partial:m117_6 # 117| r117_8(glval) = FieldAddress[y] : r117_1 # 117| r117_9(glval) = VariableAddress[y] : -# 117| r117_10(int) = Load : &:r117_9, m116_9 +# 117| r117_10(int) = Load : &:r117_9, m116_8 # 117| m117_11(int) = Store : &:r117_8, r117_10 # 117| m117_12(Point) = Chi : total:m117_7, partial:m117_11 # 118| r118_1(glval) = VariableAddress[b] : @@ -503,10 +480,9 @@ ssa.cpp: # 119| m119_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 119| m119_10(Point) = Chi : total:m117_12, partial:m119_9 # 120| v120_1(void) = NoOp : -# 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = UnmodeledUse : mu* -# 116| v116_12(void) = AliasedUse : ~m119_7 -# 116| v116_13(void) = ExitFunction : +# 116| v116_9(void) = ReturnVoid : +# 116| v116_10(void) = AliasedUse : ~m119_7 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -514,13 +490,12 @@ ssa.cpp: # 122| m122_2(unknown) = AliasedDefinition : # 122| m122_3(unknown) = InitializeNonLocal : # 122| m122_4(unknown) = Chi : total:m122_2, partial:m122_3 -# 122| mu122_5(unknown) = UnmodeledDefinition : -# 122| r122_6(glval) = VariableAddress[c] : -# 122| m122_7(bool) = InitializeParameter[c] : &:r122_6 -# 122| r122_8(glval) = VariableAddress[x1] : -# 122| m122_9(int) = InitializeParameter[x1] : &:r122_8 -# 122| r122_10(glval) = VariableAddress[x2] : -# 122| m122_11(int) = InitializeParameter[x2] : &:r122_10 +# 122| r122_5(glval) = VariableAddress[c] : +# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 +# 122| r122_7(glval) = VariableAddress[x1] : +# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 +# 122| r122_9(glval) = VariableAddress[x2] : +# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 # 123| r123_1(glval) = VariableAddress[a] : # 123| m123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -532,14 +507,14 @@ ssa.cpp: # 123| m123_9(int) = Store : &:r123_7, r123_8 # 123| m123_10(Point) = Chi : total:m123_6, partial:m123_9 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_7 +# 124| r124_2(bool) = Load : &:r124_1, m122_6 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_9 +# 125| r125_2(int) = Load : &:r125_1, m122_8 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| m125_5(int) = Store : &:r125_4, r125_2 @@ -548,7 +523,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_11 +# 128| r128_2(int) = Load : &:r128_1, m122_10 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| m128_5(int) = Store : &:r128_4, r128_2 @@ -568,10 +543,9 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, m130_2 # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = UnmodeledUse : mu* -# 122| v122_14(void) = AliasedUse : m122_3 -# 122| v122_15(void) = ExitFunction : +# 122| v122_11(void) = ReturnVoid : +# 122| v122_12(void) = AliasedUse : m122_3 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -579,13 +553,12 @@ ssa.cpp: # 134| m134_2(unknown) = AliasedDefinition : # 134| m134_3(unknown) = InitializeNonLocal : # 134| m134_4(unknown) = Chi : total:m134_2, partial:m134_3 -# 134| mu134_5(unknown) = UnmodeledDefinition : -# 134| r134_6(glval) = VariableAddress[c] : -# 134| m134_7(bool) = InitializeParameter[c] : &:r134_6 -# 134| r134_8(glval) = VariableAddress[p] : -# 134| m134_9(Point) = InitializeParameter[p] : &:r134_8 -# 134| r134_10(glval) = VariableAddress[x1] : -# 134| m134_11(int) = InitializeParameter[x1] : &:r134_10 +# 134| r134_5(glval) = VariableAddress[c] : +# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 +# 134| r134_7(glval) = VariableAddress[p] : +# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 +# 134| r134_9(glval) = VariableAddress[x1] : +# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 # 135| r135_1(glval) = VariableAddress[a] : # 135| m135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -597,14 +570,14 @@ ssa.cpp: # 135| m135_9(int) = Store : &:r135_7, r135_8 # 135| m135_10(Point) = Chi : total:m135_6, partial:m135_9 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_7 +# 136| r136_2(bool) = Load : &:r136_1, m134_6 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_11 +# 137| r137_2(int) = Load : &:r137_1, m134_10 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| m137_5(int) = Store : &:r137_4, r137_2 @@ -613,7 +586,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_9 +# 140| r140_2(Point) = Load : &:r140_1, m134_8 # 140| r140_3(glval) = VariableAddress[a] : # 140| m140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -627,10 +600,9 @@ ssa.cpp: # 142| r142_6(int) = Load : &:r142_5, m142_1 # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : -# 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = UnmodeledUse : mu* -# 134| v134_14(void) = AliasedUse : m134_3 -# 134| v134_15(void) = ExitFunction : +# 134| v134_11(void) = ReturnVoid : +# 134| v134_12(void) = AliasedUse : m134_3 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -638,13 +610,12 @@ ssa.cpp: # 145| m145_2(unknown) = AliasedDefinition : # 145| m145_3(unknown) = InitializeNonLocal : # 145| m145_4(unknown) = Chi : total:m145_2, partial:m145_3 -# 145| mu145_5(unknown) = UnmodeledDefinition : -# 145| r145_6(glval) = VariableAddress[c] : -# 145| m145_7(bool) = InitializeParameter[c] : &:r145_6 -# 145| r145_8(glval) = VariableAddress[p] : -# 145| m145_9(Point) = InitializeParameter[p] : &:r145_8 -# 145| r145_10(glval) = VariableAddress[x1] : -# 145| m145_11(int) = InitializeParameter[x1] : &:r145_10 +# 145| r145_5(glval) = VariableAddress[c] : +# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 +# 145| r145_7(glval) = VariableAddress[p] : +# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 +# 145| r145_9(glval) = VariableAddress[x1] : +# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 # 146| r146_1(glval) = VariableAddress[a] : # 146| m146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -656,14 +627,14 @@ ssa.cpp: # 146| m146_9(int) = Store : &:r146_7, r146_8 # 146| m146_10(Point) = Chi : total:m146_6, partial:m146_9 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_7 +# 147| r147_2(bool) = Load : &:r147_1, m145_6 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_11 +# 148| r148_2(int) = Load : &:r148_1, m145_10 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| m148_5(int) = Store : &:r148_4, r148_2 @@ -672,7 +643,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_9 +# 151| r151_2(Point) = Load : &:r151_1, m145_8 # 151| r151_3(glval) = VariableAddress[a] : # 151| m151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -684,10 +655,9 @@ ssa.cpp: # 153| r153_4(Point) = Load : &:r153_3, m153_1 # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : -# 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = UnmodeledUse : mu* -# 145| v145_14(void) = AliasedUse : m145_3 -# 145| v145_15(void) = ExitFunction : +# 145| v145_11(void) = ReturnVoid : +# 145| v145_12(void) = AliasedUse : m145_3 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -695,13 +665,12 @@ ssa.cpp: # 156| m156_2(unknown) = AliasedDefinition : # 156| m156_3(unknown) = InitializeNonLocal : # 156| m156_4(unknown) = Chi : total:m156_2, partial:m156_3 -# 156| mu156_5(unknown) = UnmodeledDefinition : -# 156| r156_6(glval) = VariableAddress[c] : -# 156| m156_7(bool) = InitializeParameter[c] : &:r156_6 -# 156| r156_8(glval) = VariableAddress[r] : -# 156| m156_9(Rect) = InitializeParameter[r] : &:r156_8 -# 156| r156_10(glval) = VariableAddress[x1] : -# 156| m156_11(int) = InitializeParameter[x1] : &:r156_10 +# 156| r156_5(glval) = VariableAddress[c] : +# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 +# 156| r156_7(glval) = VariableAddress[r] : +# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 +# 156| r156_9(glval) = VariableAddress[x1] : +# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 # 157| r157_1(glval) = VariableAddress[a] : # 157| m157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -713,14 +682,14 @@ ssa.cpp: # 157| m157_9(Point) = Store : &:r157_7, r157_8 # 157| m157_10(Rect) = Chi : total:m157_6, partial:m157_9 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_7 +# 158| r158_2(bool) = Load : &:r158_1, m156_6 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_11 +# 159| r159_2(int) = Load : &:r159_1, m156_10 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -730,7 +699,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_9 +# 162| r162_2(Rect) = Load : &:r162_1, m156_8 # 162| r162_3(glval) = VariableAddress[a] : # 162| m162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -743,10 +712,9 @@ ssa.cpp: # 164| r164_5(Point) = Load : &:r164_4, ~m164_1 # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : -# 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = UnmodeledUse : mu* -# 156| v156_14(void) = AliasedUse : m156_3 -# 156| v156_15(void) = ExitFunction : +# 156| v156_11(void) = ReturnVoid : +# 156| v156_12(void) = AliasedUse : m156_3 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -754,17 +722,16 @@ ssa.cpp: # 171| m171_2(unknown) = AliasedDefinition : # 171| m171_3(unknown) = InitializeNonLocal : # 171| m171_4(unknown) = Chi : total:m171_2, partial:m171_3 -# 171| mu171_5(unknown) = UnmodeledDefinition : -# 171| r171_6(glval) = VariableAddress[w] : -# 171| m171_7(Wrapper) = InitializeParameter[w] : &:r171_6 +# 171| r171_5(glval) = VariableAddress[w] : +# 171| m171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, m171_7 +# 172| r172_3(Wrapper) = Load : &:r172_2, m171_6 # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~m171_7 +# 173| r173_4(int) = Load : &:r173_3, ~m171_6 # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -780,10 +747,9 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = UnmodeledUse : mu* -# 171| v171_10(void) = AliasedUse : m171_3 -# 171| v171_11(void) = ExitFunction : +# 171| v171_7(void) = ReturnVoid : +# 171| v171_8(void) = AliasedUse : m171_3 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -791,24 +757,22 @@ ssa.cpp: # 179| m179_2(unknown) = AliasedDefinition : # 179| m179_3(unknown) = InitializeNonLocal : # 179| m179_4(unknown) = Chi : total:m179_2, partial:m179_3 -# 179| mu179_5(unknown) = UnmodeledDefinition : -# 179| r179_6(glval) = VariableAddress[p] : -# 179| m179_7(int *) = InitializeParameter[p] : &:r179_6 -# 179| r179_8(int *) = Load : &:r179_6, m179_7 -# 179| m179_9(unknown) = InitializeIndirection[p] : &:r179_8 +# 179| r179_5(glval) = VariableAddress[p] : +# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 +# 179| r179_7(int *) = Load : &:r179_5, m179_6 +# 179| m179_8(unknown) = InitializeIndirection[p] : &:r179_7 # 180| m180_1(unknown) = InlineAsm : ~m179_4 # 180| m180_2(unknown) = Chi : total:m179_4, partial:m180_1 # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_7 -# 181| r181_4(int) = Load : &:r181_3, ~m179_9 +# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_4(int) = Load : &:r181_3, ~m179_8 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 -# 179| r179_11(glval) = VariableAddress[#return] : -# 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = UnmodeledUse : mu* -# 179| v179_14(void) = AliasedUse : ~m180_2 -# 179| v179_15(void) = ExitFunction : +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, m179_8 +# 179| r179_10(glval) = VariableAddress[#return] : +# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 +# 179| v179_12(void) = AliasedUse : ~m180_2 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -816,46 +780,44 @@ ssa.cpp: # 184| m184_2(unknown) = AliasedDefinition : # 184| m184_3(unknown) = InitializeNonLocal : # 184| m184_4(unknown) = Chi : total:m184_2, partial:m184_3 -# 184| mu184_5(unknown) = UnmodeledDefinition : -# 184| r184_6(glval) = VariableAddress[a] : -# 184| m184_7(unsigned int &) = InitializeParameter[a] : &:r184_6 -# 184| r184_8(unsigned int &) = Load : &:r184_6, m184_7 -# 184| m184_9(unknown) = InitializeIndirection[a] : &:r184_8 -# 184| r184_10(glval) = VariableAddress[b] : -# 184| m184_11(unsigned int &) = InitializeParameter[b] : &:r184_10 -# 184| r184_12(unsigned int &) = Load : &:r184_10, m184_11 -# 184| m184_13(unknown) = InitializeIndirection[b] : &:r184_12 -# 184| r184_14(glval) = VariableAddress[c] : -# 184| m184_15(unsigned int &) = InitializeParameter[c] : &:r184_14 -# 184| r184_16(unsigned int &) = Load : &:r184_14, m184_15 -# 184| m184_17(unknown) = InitializeIndirection[c] : &:r184_16 -# 184| r184_18(glval) = VariableAddress[d] : -# 184| m184_19(unsigned int &) = InitializeParameter[d] : &:r184_18 -# 184| r184_20(unsigned int &) = Load : &:r184_18, m184_19 -# 184| m184_21(unknown) = InitializeIndirection[d] : &:r184_20 +# 184| r184_5(glval) = VariableAddress[a] : +# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 +# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 +# 184| m184_8(unknown) = InitializeIndirection[a] : &:r184_7 +# 184| r184_9(glval) = VariableAddress[b] : +# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 +# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 +# 184| m184_12(unknown) = InitializeIndirection[b] : &:r184_11 +# 184| r184_13(glval) = VariableAddress[c] : +# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 +# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 +# 184| m184_16(unknown) = InitializeIndirection[c] : &:r184_15 +# 184| r184_17(glval) = VariableAddress[d] : +# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 +# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 +# 184| m184_20(unknown) = InitializeIndirection[d] : &:r184_19 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_7 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_11 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_15 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_17 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_16 # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_19 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_21 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_20 # 186| m186_1(unknown) = InlineAsm : ~m184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 186| m186_2(unknown) = Chi : total:m184_4, partial:m186_1 # 192| v192_1(void) = NoOp : -# 184| v184_22(void) = ReturnIndirection[a] : &:r184_8, m184_9 -# 184| v184_23(void) = ReturnIndirection[b] : &:r184_12, m184_13 -# 184| v184_24(void) = ReturnIndirection[c] : &:r184_16, m184_17 -# 184| v184_25(void) = ReturnIndirection[d] : &:r184_20, m184_21 -# 184| v184_26(void) = ReturnVoid : -# 184| v184_27(void) = UnmodeledUse : mu* -# 184| v184_28(void) = AliasedUse : ~m186_2 -# 184| v184_29(void) = ExitFunction : +# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, m184_8 +# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, m184_12 +# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, m184_16 +# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, m184_20 +# 184| v184_25(void) = ReturnVoid : +# 184| v184_26(void) = AliasedUse : ~m186_2 +# 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -863,42 +825,41 @@ ssa.cpp: # 198| m198_2(unknown) = AliasedDefinition : # 198| m198_3(unknown) = InitializeNonLocal : # 198| m198_4(unknown) = Chi : total:m198_2, partial:m198_3 -# 198| mu198_5(unknown) = UnmodeledDefinition : -# 198| r198_6(glval) = VariableAddress[str1] : -# 198| m198_7(char *) = InitializeParameter[str1] : &:r198_6 -# 198| r198_8(char *) = Load : &:r198_6, m198_7 -# 198| m198_9(unknown) = InitializeIndirection[str1] : &:r198_8 -# 198| r198_10(glval) = VariableAddress[str2] : -# 198| m198_11(char *) = InitializeParameter[str2] : &:r198_10 -# 198| r198_12(char *) = Load : &:r198_10, m198_11 -# 198| m198_13(unknown) = InitializeIndirection[str2] : &:r198_12 -# 198| r198_14(glval) = VariableAddress[x] : -# 198| m198_15(int) = InitializeParameter[x] : &:r198_14 +# 198| r198_5(glval) = VariableAddress[str1] : +# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 +# 198| r198_7(char *) = Load : &:r198_5, m198_6 +# 198| m198_8(unknown) = InitializeIndirection[str1] : &:r198_7 +# 198| r198_9(glval) = VariableAddress[str2] : +# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 +# 198| r198_11(char *) = Load : &:r198_9, m198_10 +# 198| m198_12(unknown) = InitializeIndirection[str2] : &:r198_11 +# 198| r198_13(glval) = VariableAddress[x] : +# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_7 +# 199| r199_4(char *) = Load : &:r199_3, m198_6 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_11 +# 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_8 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_12 # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_7 +# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_8 # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_15 +# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -908,13 +869,12 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_16(void) = ReturnIndirection[str1] : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 -# 198| r198_18(glval) = VariableAddress[#return] : -# 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = UnmodeledUse : mu* -# 198| v198_21(void) = AliasedUse : m198_3 -# 198| v198_22(void) = ExitFunction : +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, m198_8 +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, m198_12 +# 198| r198_17(glval) = VariableAddress[#return] : +# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 +# 198| v198_19(void) = AliasedUse : m198_3 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -922,9 +882,8 @@ ssa.cpp: # 207| m207_2(unknown) = AliasedDefinition : # 207| m207_3(unknown) = InitializeNonLocal : # 207| m207_4(unknown) = Chi : total:m207_2, partial:m207_3 -# 207| mu207_5(unknown) = UnmodeledDefinition : -# 207| r207_6(glval) = VariableAddress[x] : -# 207| m207_7(int) = InitializeParameter[x] : &:r207_6 +# 207| r207_5(glval) = VariableAddress[x] : +# 207| m207_6(int) = InitializeParameter[x] : &:r207_5 # 208| r208_1(glval) = VariableAddress[y] : # 208| m208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -936,18 +895,17 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_7 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_6 # 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 209| m209_12(int) = Chi : total:m208_2, partial:m209_11 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, m209_12 # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_8(glval) = VariableAddress[#return] : -# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 -# 207| v207_10(void) = UnmodeledUse : mu* -# 207| v207_11(void) = AliasedUse : m207_3 -# 207| v207_12(void) = ExitFunction : +# 207| r207_7(glval) = VariableAddress[#return] : +# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 +# 207| v207_9(void) = AliasedUse : m207_3 +# 207| v207_10(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -955,7 +913,6 @@ ssa.cpp: # 213| m213_2(unknown) = AliasedDefinition : # 213| m213_3(unknown) = InitializeNonLocal : # 213| m213_4(unknown) = Chi : total:m213_2, partial:m213_3 -# 213| mu213_5(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m213_3 @@ -1013,10 +970,9 @@ ssa.cpp: # 221| m221_11(unknown[2]) = Store : &:r221_9, r221_10 # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : -# 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = UnmodeledUse : mu* -# 213| v213_8(void) = AliasedUse : m213_3 -# 213| v213_9(void) = ExitFunction : +# 213| v213_5(void) = ReturnVoid : +# 213| v213_6(void) = AliasedUse : m213_3 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1024,7 +980,6 @@ ssa.cpp: # 226| m226_2(unknown) = AliasedDefinition : # 226| m226_3(unknown) = InitializeNonLocal : # 226| m226_4(unknown) = Chi : total:m226_2, partial:m226_3 -# 226| mu226_5(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| m227_3(unknown) = ^CallSideEffect : ~m226_4 @@ -1040,41 +995,44 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m226_3 # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_6(glval) = VariableAddress[#return] : -# 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = UnmodeledUse : mu* -# 226| v226_9(void) = AliasedUse : ~m227_4 -# 226| v226_10(void) = ExitFunction : +# 226| r226_5(glval) = VariableAddress[#return] : +# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 +# 226| v226_7(void) = AliasedUse : ~m227_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| m235_2(unknown) = AliasedDefinition : -# 235| m235_3(unknown) = InitializeNonLocal : -# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| mu235_5(unknown) = UnmodeledDefinition : -# 235| r235_6(glval) = InitializeThis : -# 235| r235_7(glval) = VariableAddress[x] : -# 235| m235_8(int) = InitializeParameter[x] : &:r235_7 -# 235| v235_9(void) = NoOp : -# 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : m235_3 -# 235| v235_13(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| m235_2(unknown) = AliasedDefinition : +# 235| m235_3(unknown) = InitializeNonLocal : +# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 +# 235| r235_5(glval) = VariableAddress[#this] : +# 235| m235_6(glval) = InitializeParameter[#this] : &:r235_5 +# 235| r235_7(glval) = Load : &:r235_5, m235_6 +# 235| m235_8(Constructible) = InitializeIndirection[#this] : &:r235_7 +# 235| r235_9(glval) = VariableAddress[x] : +# 235| m235_10(int) = InitializeParameter[x] : &:r235_9 +# 235| v235_11(void) = NoOp : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| mu236_5(unknown) = UnmodeledDefinition : -# 236| r236_6(glval) = InitializeThis : -# 236| v236_7(void) = NoOp : -# 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = UnmodeledUse : mu* -# 236| v236_10(void) = AliasedUse : m236_3 -# 236| v236_11(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = VariableAddress[#this] : +# 236| m236_6(glval) = InitializeParameter[#this] : &:r236_5 +# 236| r236_7(glval) = Load : &:r236_5, m236_6 +# 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 +# 236| v236_9(void) = NoOp : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1082,7 +1040,6 @@ ssa.cpp: # 239| m239_2(unknown) = AliasedDefinition : # 239| m239_3(unknown) = InitializeNonLocal : # 239| m239_4(unknown) = Chi : total:m239_2, partial:m239_3 -# 239| mu239_5(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| m240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1126,10 +1083,9 @@ ssa.cpp: # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : -# 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = UnmodeledUse : mu* -# 239| v239_8(void) = AliasedUse : ~m244_5 -# 239| v239_9(void) = ExitFunction : +# 239| v239_5(void) = ReturnVoid : +# 239| v239_6(void) = AliasedUse : ~m244_5 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1137,17 +1093,16 @@ ssa.cpp: # 247| m247_2(unknown) = AliasedDefinition : # 247| m247_3(unknown) = InitializeNonLocal : # 247| m247_4(unknown) = Chi : total:m247_2, partial:m247_3 -# 247| mu247_5(unknown) = UnmodeledDefinition : -# 247| r247_6(glval) = VariableAddress[src] : -# 247| m247_7(char *) = InitializeParameter[src] : &:r247_6 -# 247| r247_8(char *) = Load : &:r247_6, m247_7 -# 247| m247_9(unknown) = InitializeIndirection[src] : &:r247_8 -# 247| r247_10(glval) = VariableAddress[size] : -# 247| m247_11(int) = InitializeParameter[size] : &:r247_10 +# 247| r247_5(glval) = VariableAddress[src] : +# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 +# 247| r247_7(char *) = Load : &:r247_5, m247_6 +# 247| m247_8(unknown) = InitializeIndirection[src] : &:r247_7 +# 247| r247_9(glval) = VariableAddress[size] : +# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_11 +# 248| r248_4(int) = Load : &:r248_3, m247_10 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 @@ -1159,19 +1114,19 @@ ssa.cpp: # 248| m248_13(char *) = Store : &:r248_1, r248_12 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_7 +# 249| r249_3(char *) = Load : &:r249_2, m247_6 # 249| r249_4(glval) = CopyValue : r249_3 # 249| m249_5(char) = Store : &:r249_4, r249_1 -# 249| m249_6(unknown) = Chi : total:m247_9, partial:m249_5 +# 249| m249_6(unknown) = Chi : total:m247_8, partial:m249_5 # 250| r250_1(glval) = FunctionAddress[memcpy] : # 250| r250_2(glval) = VariableAddress[dst] : # 250| r250_3(char *) = Load : &:r250_2, m248_13 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_7 +# 250| r250_6(char *) = Load : &:r250_5, m247_6 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_11 +# 250| r250_9(int) = Load : &:r250_8, m247_10 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m249_6 # 250| m250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1180,12 +1135,11 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_13 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_12(void) = ReturnIndirection[src] : &:r247_8, m249_6 -# 247| r247_13(glval) = VariableAddress[#return] : -# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 -# 247| v247_15(void) = UnmodeledUse : mu* -# 247| v247_16(void) = AliasedUse : ~m248_10 -# 247| v247_17(void) = ExitFunction : +# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, m249_6 +# 247| r247_12(glval) = VariableAddress[#return] : +# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 +# 247| v247_14(void) = AliasedUse : ~m248_10 +# 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1193,11 +1147,10 @@ ssa.cpp: # 254| m254_2(unknown) = AliasedDefinition : # 254| m254_3(unknown) = InitializeNonLocal : # 254| m254_4(unknown) = Chi : total:m254_2, partial:m254_3 -# 254| mu254_5(unknown) = UnmodeledDefinition : -# 254| r254_6(glval) = VariableAddress[b] : -# 254| m254_7(bool) = InitializeParameter[b] : &:r254_6 +# 254| r254_5(glval) = VariableAddress[b] : +# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_7 +# 255| r255_2(bool) = Load : &:r255_1, m254_6 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1229,11 +1182,10 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m254_3 # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_8(glval) = VariableAddress[#return] : -# 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = UnmodeledUse : mu* -# 254| v254_11(void) = AliasedUse : ~m262_1 -# 254| v254_12(void) = ExitFunction : +# 254| r254_7(glval) = VariableAddress[#return] : +# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 +# 254| v254_9(void) = AliasedUse : ~m262_1 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1241,17 +1193,16 @@ ssa.cpp: # 268| m268_2(unknown) = AliasedDefinition : # 268| m268_3(unknown) = InitializeNonLocal : # 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 -# 268| mu268_5(unknown) = UnmodeledDefinition : -# 268| r268_6(glval) = VariableAddress[s] : -# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 -# 268| r268_8(void *) = Load : &:r268_6, m268_7 -# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 -# 268| r268_10(glval) = VariableAddress[size] : -# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| m268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| r268_9(glval) = VariableAddress[size] : +# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_11 +# 269| r269_4(int) = Load : &:r269_3, m268_10 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 # 269| m269_6(unknown) = ^CallSideEffect : ~m268_4 # 269| m269_7(unknown) = Chi : total:m268_4, partial:m269_6 @@ -1261,23 +1212,22 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_9 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_5(void *) = Load : &:r270_4, m268_6 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_11 +# 270| r270_7(int) = Load : &:r270_6, m268_10 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_9 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_8 # 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_9 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_12(void) = ReturnIndirection[s] : &:r268_8, m268_9 -# 268| r268_13(glval) = VariableAddress[#return] : -# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 -# 268| v268_15(void) = UnmodeledUse : mu* -# 268| v268_16(void) = AliasedUse : ~m269_7 -# 268| v268_17(void) = ExitFunction : +# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, m268_8 +# 268| r268_12(glval) = VariableAddress[#return] : +# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 +# 268| v268_14(void) = AliasedUse : ~m269_7 +# 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1285,13 +1235,12 @@ ssa.cpp: # 275| m275_2(unknown) = AliasedDefinition : # 275| m275_3(unknown) = InitializeNonLocal : # 275| m275_4(unknown) = Chi : total:m275_2, partial:m275_3 -# 275| mu275_5(unknown) = UnmodeledDefinition : -# 275| r275_6(glval) = VariableAddress[c] : -# 275| m275_7(bool) = InitializeParameter[c] : &:r275_6 -# 275| r275_8(glval) = VariableAddress[p] : -# 275| m275_9(Point) = InitializeParameter[p] : &:r275_8 -# 275| r275_10(glval) = VariableAddress[x1] : -# 275| m275_11(int) = InitializeParameter[x1] : &:r275_10 +# 275| r275_5(glval) = VariableAddress[c] : +# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 +# 275| r275_7(glval) = VariableAddress[p] : +# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 +# 275| r275_9(glval) = VariableAddress[x1] : +# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 # 276| r276_1(glval) = VariableAddress[a] : # 276| m276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1308,14 +1257,14 @@ ssa.cpp: # 277| m277_4(Point *) = Store : &:r277_3, r277_2 # 277| m277_5(unknown) = Chi : total:m275_4, partial:m277_4 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_7 +# 278| r278_2(bool) = Load : &:r278_1, m275_6 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_11 +# 279| r279_2(int) = Load : &:r279_1, m275_10 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| m279_5(int) = Store : &:r279_4, r279_2 @@ -1331,59 +1280,64 @@ ssa.cpp: # 281| r281_6(int) = Load : &:r281_5, m281_1 # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : -# 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = UnmodeledUse : mu* -# 275| v275_14(void) = AliasedUse : ~m277_5 -# 275| v275_15(void) = ExitFunction : +# 275| v275_11(void) = ReturnVoid : +# 275| v275_12(void) = AliasedUse : ~m277_5 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| m286_2(unknown) = AliasedDefinition : -# 286| m286_3(unknown) = InitializeNonLocal : -# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| mu286_5(unknown) = UnmodeledDefinition : -# 286| r286_6(glval) = InitializeThis : -# 286| r286_7(glval) = VariableAddress[x] : -# 286| m286_8(int) = InitializeParameter[x] : &:r286_7 -# 286| v286_9(void) = NoOp : -# 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = UnmodeledUse : mu* -# 286| v286_12(void) = AliasedUse : m286_3 -# 286| v286_13(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| m286_2(unknown) = AliasedDefinition : +# 286| m286_3(unknown) = InitializeNonLocal : +# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 +# 286| r286_5(glval) = VariableAddress[#this] : +# 286| m286_6(glval) = InitializeParameter[#this] : &:r286_5 +# 286| r286_7(glval) = Load : &:r286_5, m286_6 +# 286| m286_8(A) = InitializeIndirection[#this] : &:r286_7 +# 286| r286_9(glval) = VariableAddress[x] : +# 286| m286_10(int) = InitializeParameter[x] : &:r286_9 +# 286| v286_11(void) = NoOp : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| m287_2(unknown) = AliasedDefinition : -# 287| m287_3(unknown) = InitializeNonLocal : -# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| mu287_5(unknown) = UnmodeledDefinition : -# 287| r287_6(glval) = InitializeThis : -# 287| r287_7(glval) = VariableAddress[p#0] : -# 287| m287_8(A *) = InitializeParameter[p#0] : &:r287_7 -# 287| r287_9(A *) = Load : &:r287_7, m287_8 -# 287| m287_10(unknown) = InitializeIndirection[p#0] : &:r287_9 -# 287| v287_11(void) = NoOp : -# 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 -# 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = UnmodeledUse : mu* -# 287| v287_15(void) = AliasedUse : m287_3 -# 287| v287_16(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| m287_2(unknown) = AliasedDefinition : +# 287| m287_3(unknown) = InitializeNonLocal : +# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 +# 287| r287_5(glval) = VariableAddress[#this] : +# 287| m287_6(glval) = InitializeParameter[#this] : &:r287_5 +# 287| r287_7(glval) = Load : &:r287_5, m287_6 +# 287| m287_8(A) = InitializeIndirection[#this] : &:r287_7 +# 287| r287_9(glval) = VariableAddress[p#0] : +# 287| m287_10(A *) = InitializeParameter[p#0] : &:r287_9 +# 287| r287_11(A *) = Load : &:r287_9, m287_10 +# 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 +# 287| v287_13(void) = NoOp : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| mu288_5(unknown) = UnmodeledDefinition : -# 288| r288_6(glval) = InitializeThis : -# 288| v288_7(void) = NoOp : -# 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = UnmodeledUse : mu* -# 288| v288_10(void) = AliasedUse : m288_3 -# 288| v288_11(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = VariableAddress[#this] : +# 288| m288_6(glval) = InitializeParameter[#this] : &:r288_5 +# 288| r288_7(glval) = Load : &:r288_5, m288_6 +# 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 +# 288| v288_9(void) = NoOp : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1391,9 +1345,8 @@ ssa.cpp: # 291| m291_2(unknown) = AliasedDefinition : # 291| m291_3(unknown) = InitializeNonLocal : # 291| m291_4(unknown) = Chi : total:m291_2, partial:m291_3 -# 291| mu291_5(unknown) = UnmodeledDefinition : -# 291| r291_6(glval) = VariableAddress[x] : -# 291| m291_7(int) = InitializeParameter[x] : &:r291_6 +# 291| r291_5(glval) = VariableAddress[x] : +# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1430,7 +1383,7 @@ ssa.cpp: # 294| r294_16(A *) = Convert : r294_12 # 294| r294_17(glval) = FunctionAddress[A] : # 294| r294_18(glval) = VariableAddress[x] : -# 294| r294_19(int) = Load : &:r294_18, m291_7 +# 294| r294_19(int) = Load : &:r294_18, m291_6 # 294| v294_20(void) = Call : func:r294_17, this:r294_16, 0:r294_19 # 294| m294_21(unknown) = ^CallSideEffect : ~m294_14 # 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21 @@ -1466,11 +1419,10 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_9 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_8(glval) = VariableAddress[#return] : -# 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = UnmodeledUse : mu* -# 291| v291_11(void) = AliasedUse : ~m295_12 -# 291| v291_12(void) = ExitFunction : +# 291| r291_7(glval) = VariableAddress[#return] : +# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 +# 291| v291_9(void) = AliasedUse : ~m295_12 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1478,45 +1430,68 @@ ssa.cpp: # 301| m301_2(unknown) = AliasedDefinition : # 301| m301_3(unknown) = InitializeNonLocal : # 301| m301_4(unknown) = Chi : total:m301_2, partial:m301_3 -# 301| mu301_5(unknown) = UnmodeledDefinition : -# 301| r301_6(glval) = VariableAddress[argc] : -# 301| m301_7(int) = InitializeParameter[argc] : &:r301_6 -# 301| r301_8(glval) = VariableAddress[argv] : -# 301| m301_9(char **) = InitializeParameter[argv] : &:r301_8 -# 301| r301_10(char **) = Load : &:r301_8, m301_9 -# 301| m301_11(unknown) = InitializeIndirection[argv] : &:r301_10 +# 301| r301_5(glval) = VariableAddress[argc] : +# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 +# 301| r301_7(glval) = VariableAddress[argv] : +# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 +# 301| r301_9(char **) = Load : &:r301_7, m301_8 +# 301| m301_10(unknown) = InitializeIndirection[argv] : &:r301_9 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_3(int) = Load : &:r302_2, m301_6 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 # 302| m302_7(unknown) = ^CallSideEffect : ~m301_4 # 302| m302_8(unknown) = Chi : total:m301_4, partial:m302_7 -# 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m301_11 +# 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m301_10 # 302| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 -# 302| m302_11(char *) = Chi : total:m301_11, partial:m302_10 +# 302| m302_11(unknown) = Chi : total:m301_10, partial:m302_10 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_7 +# 303| r303_3(int) = Load : &:r303_2, m301_6 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| m303_7(unknown) = ^CallSideEffect : ~m302_8 # 303| m303_8(unknown) = Chi : total:m302_8, partial:m303_7 # 303| v303_9(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m302_11 # 303| m303_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 -# 303| m303_11(char *) = Chi : total:m302_11, partial:m303_10 +# 303| m303_11(unknown) = Chi : total:m302_11, partial:m303_10 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_9 +# 304| r304_3(char **) = Load : &:r304_2, m301_8 # 304| r304_4(char *) = Load : &:r304_3, ~m303_11 # 304| r304_5(char) = Load : &:r304_4, ~m303_8 # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11, m303_11 -# 301| r301_13(glval) = VariableAddress[#return] : -# 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 -# 301| v301_15(void) = UnmodeledUse : mu* -# 301| v301_16(void) = AliasedUse : ~m303_8 -# 301| v301_17(void) = ExitFunction : +# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, m303_11 +# 301| r301_12(glval) = VariableAddress[#return] : +# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 +# 301| v301_14(void) = AliasedUse : ~m303_8 +# 301| v301_15(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| m310_2(unknown) = AliasedDefinition : +# 310| m310_3(unknown) = InitializeNonLocal : +# 310| m310_4(unknown) = Chi : total:m310_2, partial:m310_3 +# 310| r310_5(glval) = VariableAddress[#this] : +# 310| m310_6(glval) = InitializeParameter[#this] : &:r310_5 +# 310| r310_7(glval) = Load : &:r310_5, m310_6 +# 310| m310_8(ThisAliasTest) = InitializeIndirection[#this] : &:r310_7 +# 310| r310_9(glval) = VariableAddress[arg] : +# 310| m310_10(int) = InitializeParameter[arg] : &:r310_9 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_10 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_6 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| m311_6(int) = Store : &:r311_5, r311_2 +# 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 +# 312| v312_1(void) = NoOp : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql deleted file mode 100644 index 74fa11944a6..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected deleted file mode 100644 index f448013286b..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected +++ /dev/null @@ -1,29 +0,0 @@ -missingOperand -unexpectedOperand -duplicateOperand -| ssa.cpp:301:27:301:30 | ReturnIndirection: argv | Instruction has 2 operands with tag 'SideEffect' in function '$@'. | ssa.cpp:301:5:301:8 | IR: main | int main(int, char**) | -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -| ssa.cpp:301:27:301:30 | SideEffect | MemoryOperand 'SideEffect' has a `getDefinitionOverlap()` of 'MayPartiallyOverlap'. | ssa.cpp:301:5:301:8 | IR: main | int main(int, char**) | -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes -missingCppType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected new file mode 100644 index 00000000000..21782bd5ef1 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected @@ -0,0 +1,3 @@ +multipleOperandMemoryLocations +missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql similarity index 90% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql index b3962e34648..b9d03404338 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected new file mode 100644 index 00000000000..21782bd5ef1 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected @@ -0,0 +1,3 @@ +multipleOperandMemoryLocations +missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..d0a29f0641a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected deleted file mode 100644 index 7c2d1faf639..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.expected deleted file mode 100644 index 7c2d1faf639..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 8e348011785..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 5ea3ef77968..b8788c5c6aa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -302,4 +302,12 @@ int main(int argc, char **argv) { unknownFunction(argc, argv); unknownFunction(argc, argv); return **argv; // Chi chain goes through side effects from unknownFunction -} \ No newline at end of file +} + +class ThisAliasTest { + int x, y; + + void setX(int arg) { + this->x = arg; + } +}; \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected similarity index 95% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql new file mode 100644 index 00000000000..6507642d86a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected new file mode 100644 index 00000000000..1c41692bcaa --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected @@ -0,0 +1,28 @@ +missingOperand +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes +missingCppType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index b307db1cfc5..1d155eaf30d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -4,26 +4,25 @@ ssa.cpp: # 13| v13_1(void) = EnterFunction : # 13| mu13_2(unknown) = AliasedDefinition : # 13| mu13_3(unknown) = InitializeNonLocal : -# 13| mu13_4(unknown) = UnmodeledDefinition : -# 13| r13_5(glval) = VariableAddress[p] : -# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 -# 13| r13_7(Point *) = Load : &:r13_5, m13_6 -# 13| mu13_8(unknown) = InitializeIndirection[p] : &:r13_7 -# 13| r13_9(glval) = VariableAddress[which1] : -# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 -# 13| r13_11(glval) = VariableAddress[which2] : -# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 +# 13| r13_4(glval) = VariableAddress[p] : +# 13| m13_5(Point *) = InitializeParameter[p] : &:r13_4 +# 13| r13_6(Point *) = Load : &:r13_4, m13_5 +# 13| mu13_7(unknown) = InitializeIndirection[p] : &:r13_6 +# 13| r13_8(glval) = VariableAddress[which1] : +# 13| m13_9(bool) = InitializeParameter[which1] : &:r13_8 +# 13| r13_10(glval) = VariableAddress[which2] : +# 13| m13_11(bool) = InitializeParameter[which2] : &:r13_10 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_10 +# 14| r14_2(bool) = Load : &:r14_1, m13_9 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_6 +# 15| r15_2(Point *) = Load : &:r15_1, m13_5 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~mu13_4 +# 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| mu15_7(int) = Store : &:r15_3, r15_6 @@ -31,9 +30,9 @@ ssa.cpp: # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_6 +# 18| r18_2(Point *) = Load : &:r18_1, m13_5 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~mu13_4 +# 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| mu18_7(int) = Store : &:r18_3, r18_6 @@ -41,16 +40,16 @@ ssa.cpp: # 21| Block 3 # 21| r21_1(glval) = VariableAddress[which2] : -# 21| r21_2(bool) = Load : &:r21_1, m13_12 +# 21| r21_2(bool) = Load : &:r21_1, m13_11 # 21| v21_3(void) = ConditionalBranch : r21_2 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_6 +# 22| r22_2(Point *) = Load : &:r22_1, m13_5 # 22| r22_3(glval) = FieldAddress[x] : r22_2 -# 22| r22_4(int) = Load : &:r22_3, ~mu13_4 +# 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : # 22| r22_6(int) = Add : r22_4, r22_5 # 22| mu22_7(int) = Store : &:r22_3, r22_6 @@ -58,9 +57,9 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_6 +# 25| r25_2(Point *) = Load : &:r25_1, m13_5 # 25| r25_3(glval) = FieldAddress[y] : r25_2 -# 25| r25_4(int) = Load : &:r25_3, ~mu13_4 +# 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : # 25| r25_6(int) = Add : r25_4, r25_5 # 25| mu25_7(int) = Store : &:r25_3, r25_6 @@ -69,47 +68,43 @@ ssa.cpp: # 28| Block 6 # 28| r28_1(glval) = VariableAddress[#return] : # 28| r28_2(glval) = VariableAddress[p] : -# 28| r28_3(Point *) = Load : &:r28_2, m13_6 +# 28| r28_3(Point *) = Load : &:r28_2, m13_5 # 28| r28_4(glval) = FieldAddress[x] : r28_3 -# 28| r28_5(int) = Load : &:r28_4, ~mu13_4 +# 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : -# 28| r28_7(Point *) = Load : &:r28_6, m13_6 +# 28| r28_7(Point *) = Load : &:r28_6, m13_5 # 28| r28_8(glval) = FieldAddress[y] : r28_7 -# 28| r28_9(int) = Load : &:r28_8, ~mu13_4 +# 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 -# 13| r13_14(glval) = VariableAddress[#return] : -# 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = UnmodeledUse : mu* -# 13| v13_17(void) = AliasedUse : ~mu13_4 -# 13| v13_18(void) = ExitFunction : +# 13| v13_12(void) = ReturnIndirection[p] : &:r13_6, ~m? +# 13| r13_13(glval) = VariableAddress[#return] : +# 13| v13_14(void) = ReturnValue : &:r13_13, m28_11 +# 13| v13_15(void) = AliasedUse : ~m? +# 13| v13_16(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 # 31| v31_1(void) = EnterFunction : # 31| mu31_2(unknown) = AliasedDefinition : # 31| mu31_3(unknown) = InitializeNonLocal : -# 31| mu31_4(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_5(glval) = VariableAddress[#return] : -# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = UnmodeledUse : mu* -# 31| v31_8(void) = AliasedUse : ~mu31_4 -# 31| v31_9(void) = ExitFunction : +# 31| r31_4(glval) = VariableAddress[#return] : +# 31| v31_5(void) = ReturnValue : &:r31_4, m35_3 +# 31| v31_6(void) = AliasedUse : ~m? +# 31| v31_7(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 # 38| v38_1(void) = EnterFunction : # 38| mu38_2(unknown) = AliasedDefinition : # 38| mu38_3(unknown) = InitializeNonLocal : -# 38| mu38_4(unknown) = UnmodeledDefinition : -# 38| r38_5(glval) = VariableAddress[b] : -# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 +# 38| r38_4(glval) = VariableAddress[b] : +# 38| m38_5(bool) = InitializeParameter[b] : &:r38_4 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -117,18 +112,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_6 +# 41| r41_2(bool) = Load : &:r41_1, m38_5 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 5 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 -# 38| r38_8(glval) = VariableAddress[#return] : -# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = UnmodeledUse : mu* -# 38| v38_11(void) = AliasedUse : ~mu38_4 -# 38| v38_12(void) = ExitFunction : +# 38| m38_6(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 +# 38| r38_7(glval) = VariableAddress[#return] : +# 38| v38_8(void) = ReturnValue : &:r38_7, m38_6 +# 38| v38_9(void) = AliasedUse : ~m? +# 38| v38_10(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,20 +170,19 @@ ssa.cpp: # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| mu59_2(unknown) = AliasedDefinition : -# 59| mu59_3(unknown) = InitializeNonLocal : -# 59| mu59_4(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| mu59_2(unknown) = AliasedDefinition : +# 59| mu59_3(unknown) = InitializeNonLocal : +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -198,32 +191,30 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_5(glval) = VariableAddress[#return] : -# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = UnmodeledUse : mu* -# 59| v59_8(void) = AliasedUse : ~mu59_4 -# 59| v59_9(void) = ExitFunction : +# 59| r59_4(glval) = VariableAddress[#return] : +# 59| v59_5(void) = ReturnValue : &:r59_4, m65_4 +# 59| v59_6(void) = AliasedUse : ~m? +# 59| v59_7(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_8(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 # 68| v68_1(void) = EnterFunction : # 68| mu68_2(unknown) = AliasedDefinition : # 68| mu68_3(unknown) = InitializeNonLocal : -# 68| mu68_4(unknown) = UnmodeledDefinition : -# 68| r68_5(glval) = VariableAddress[n] : -# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 -# 68| r68_7(glval) = VariableAddress[p] : -# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 -# 68| r68_9(char *) = Load : &:r68_7, m68_8 -# 68| mu68_10(unknown) = InitializeIndirection[p] : &:r68_9 +# 68| r68_4(glval) = VariableAddress[n] : +# 68| m68_5(int) = InitializeParameter[n] : &:r68_4 +# 68| r68_6(glval) = VariableAddress[p] : +# 68| m68_7(char *) = InitializeParameter[p] : &:r68_6 +# 68| r68_8(char *) = Load : &:r68_6, m68_7 +# 68| mu68_9(unknown) = InitializeIndirection[p] : &:r68_8 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_7 +# 69| m69_1(char *) = Phi : from 0:m68_7, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_5, from 2:m69_7 # 69| r69_3(glval) = VariableAddress[n] : # 69| r69_4(int) = Load : &:r69_3, m69_2 # 69| r69_5(int) = Constant[1] : @@ -250,20 +241,18 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 -# 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = UnmodeledUse : mu* -# 68| v68_14(void) = AliasedUse : ~mu68_4 -# 68| v68_15(void) = ExitFunction : +# 68| v68_10(void) = ReturnIndirection[p] : &:r68_8, ~m? +# 68| v68_11(void) = ReturnVoid : +# 68| v68_12(void) = AliasedUse : ~m? +# 68| v68_13(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 # 75| v75_1(void) = EnterFunction : # 75| mu75_2(unknown) = AliasedDefinition : # 75| mu75_3(unknown) = InitializeNonLocal : -# 75| mu75_4(unknown) = UnmodeledDefinition : -# 75| r75_5(glval) = VariableAddress[b] : -# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 +# 75| r75_4(glval) = VariableAddress[b] : +# 75| m75_5(bool) = InitializeParameter[b] : &:r75_4 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -274,7 +263,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_6 +# 79| r79_2(bool) = Load : &:r79_1, m75_5 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -310,191 +299,177 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = UnmodeledUse : mu* -# 75| v75_9(void) = AliasedUse : ~mu75_4 -# 75| v75_10(void) = ExitFunction : +# 75| v75_6(void) = ReturnVoid : +# 75| v75_7(void) = AliasedUse : ~m? +# 75| v75_8(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 # 91| v91_1(void) = EnterFunction : # 91| mu91_2(unknown) = AliasedDefinition : # 91| mu91_3(unknown) = InitializeNonLocal : -# 91| mu91_4(unknown) = UnmodeledDefinition : -# 91| r91_5(glval) = VariableAddress[a] : -# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 +# 91| r91_4(glval) = VariableAddress[a] : +# 91| m91_5(Point) = InitializeParameter[a] : &:r91_4 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_6 +# 92| r92_3(Point) = Load : &:r92_2, m91_5 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : ~mu91_4 -# 91| v91_10(void) = ExitFunction : +# 91| v91_6(void) = ReturnVoid : +# 91| v91_7(void) = AliasedUse : ~m? +# 91| v91_8(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 # 95| v95_1(void) = EnterFunction : # 95| mu95_2(unknown) = AliasedDefinition : # 95| mu95_3(unknown) = InitializeNonLocal : -# 95| mu95_4(unknown) = UnmodeledDefinition : -# 95| r95_5(glval) = VariableAddress[a] : -# 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| r95_4(glval) = VariableAddress[a] : +# 95| mu95_5(Point) = InitializeParameter[a] : &:r95_4 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, ~mu95_4 +# 96| r96_3(Point) = Load : &:r96_2, ~m? # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| mu97_6(unknown) = ^CallSideEffect : ~mu95_4 -# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~mu95_4 +# 97| mu97_6(unknown) = ^CallSideEffect : ~m? +# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : -# 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = UnmodeledUse : mu* -# 95| v95_9(void) = AliasedUse : ~mu95_4 -# 95| v95_10(void) = ExitFunction : +# 95| v95_6(void) = ReturnVoid : +# 95| v95_7(void) = AliasedUse : ~m? +# 95| v95_8(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 # 100| v100_1(void) = EnterFunction : # 100| mu100_2(unknown) = AliasedDefinition : # 100| mu100_3(unknown) = InitializeNonLocal : -# 100| mu100_4(unknown) = UnmodeledDefinition : -# 100| r100_5(glval) = VariableAddress[a] : -# 100| mu100_6(Point) = InitializeParameter[a] : &:r100_5 +# 100| r100_4(glval) = VariableAddress[a] : +# 100| mu100_5(Point) = InitializeParameter[a] : &:r100_4 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~mu100_4 +# 101| r101_4(int) = Load : &:r101_3, ~m? # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~mu100_4 +# 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = UnmodeledUse : mu* -# 100| v100_9(void) = AliasedUse : ~mu100_4 -# 100| v100_10(void) = ExitFunction : +# 100| v100_6(void) = ReturnVoid : +# 100| v100_7(void) = AliasedUse : ~m? +# 100| v100_8(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 # 105| v105_1(void) = EnterFunction : # 105| mu105_2(unknown) = AliasedDefinition : # 105| mu105_3(unknown) = InitializeNonLocal : -# 105| mu105_4(unknown) = UnmodeledDefinition : -# 105| r105_5(glval) = VariableAddress[a] : -# 105| mu105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| r105_4(glval) = VariableAddress[a] : +# 105| mu105_5(Point) = InitializeParameter[a] : &:r105_4 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~mu105_4 +# 106| r106_4(int) = Load : &:r106_3, ~m? # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~mu105_4 +# 107| r107_4(int) = Load : &:r107_3, ~m? # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| mu108_6(unknown) = ^CallSideEffect : ~mu105_4 -# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~mu105_4 +# 108| mu108_6(unknown) = ^CallSideEffect : ~m? +# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : -# 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = UnmodeledUse : mu* -# 105| v105_9(void) = AliasedUse : ~mu105_4 -# 105| v105_10(void) = ExitFunction : +# 105| v105_6(void) = ReturnVoid : +# 105| v105_7(void) = AliasedUse : ~m? +# 105| v105_8(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 # 111| v111_1(void) = EnterFunction : # 111| mu111_2(unknown) = AliasedDefinition : # 111| mu111_3(unknown) = InitializeNonLocal : -# 111| mu111_4(unknown) = UnmodeledDefinition : -# 111| r111_5(glval) = VariableAddress[x] : -# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 -# 111| r111_7(glval) = VariableAddress[y] : -# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 +# 111| r111_4(glval) = VariableAddress[x] : +# 111| m111_5(int) = InitializeParameter[x] : &:r111_4 +# 111| r111_6(glval) = VariableAddress[y] : +# 111| m111_7(int) = InitializeParameter[y] : &:r111_6 # 112| r112_1(glval) = VariableAddress[a] : # 112| mu112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_6 +# 112| r112_5(int) = Load : &:r112_4, m111_5 # 112| mu112_6(int) = Store : &:r112_3, r112_5 # 112| r112_7(glval) = FieldAddress[y] : r112_1 # 112| r112_8(glval) = VariableAddress[y] : -# 112| r112_9(int) = Load : &:r112_8, m111_8 +# 112| r112_9(int) = Load : &:r112_8, m111_7 # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : -# 113| r113_3(Point) = Load : &:r113_2, ~mu111_4 +# 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = UnmodeledUse : mu* -# 111| v111_11(void) = AliasedUse : ~mu111_4 -# 111| v111_12(void) = ExitFunction : +# 111| v111_8(void) = ReturnVoid : +# 111| v111_9(void) = AliasedUse : ~m? +# 111| v111_10(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 # 116| v116_1(void) = EnterFunction : # 116| mu116_2(unknown) = AliasedDefinition : # 116| mu116_3(unknown) = InitializeNonLocal : -# 116| mu116_4(unknown) = UnmodeledDefinition : -# 116| r116_5(glval) = VariableAddress[x] : -# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 -# 116| r116_7(glval) = VariableAddress[y] : -# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 +# 116| r116_4(glval) = VariableAddress[x] : +# 116| m116_5(int) = InitializeParameter[x] : &:r116_4 +# 116| r116_6(glval) = VariableAddress[y] : +# 116| m116_7(int) = InitializeParameter[y] : &:r116_6 # 117| r117_1(glval) = VariableAddress[a] : # 117| mu117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_6 +# 117| r117_5(int) = Load : &:r117_4, m116_5 # 117| mu117_6(int) = Store : &:r117_3, r117_5 # 117| r117_7(glval) = FieldAddress[y] : r117_1 # 117| r117_8(glval) = VariableAddress[y] : -# 117| r117_9(int) = Load : &:r117_8, m116_8 +# 117| r117_9(int) = Load : &:r117_8, m116_7 # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : -# 118| r118_3(Point) = Load : &:r118_2, ~mu116_4 +# 118| r118_3(Point) = Load : &:r118_2, ~m? # 118| m118_4(Point) = Store : &:r118_1, r118_3 # 119| r119_1(glval) = FunctionAddress[Escape] : # 119| r119_2(glval) = VariableAddress[a] : # 119| r119_3(Point *) = CopyValue : r119_2 # 119| r119_4(void *) = Convert : r119_3 # 119| v119_5(void) = Call : func:r119_1, 0:r119_4 -# 119| mu119_6(unknown) = ^CallSideEffect : ~mu116_4 -# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~mu116_4 +# 119| mu119_6(unknown) = ^CallSideEffect : ~m? +# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : -# 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = UnmodeledUse : mu* -# 116| v116_11(void) = AliasedUse : ~mu116_4 -# 116| v116_12(void) = ExitFunction : +# 116| v116_8(void) = ReturnVoid : +# 116| v116_9(void) = AliasedUse : ~m? +# 116| v116_10(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 # 122| v122_1(void) = EnterFunction : # 122| mu122_2(unknown) = AliasedDefinition : # 122| mu122_3(unknown) = InitializeNonLocal : -# 122| mu122_4(unknown) = UnmodeledDefinition : -# 122| r122_5(glval) = VariableAddress[c] : -# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 -# 122| r122_7(glval) = VariableAddress[x1] : -# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 -# 122| r122_9(glval) = VariableAddress[x2] : -# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 +# 122| r122_4(glval) = VariableAddress[c] : +# 122| m122_5(bool) = InitializeParameter[c] : &:r122_4 +# 122| r122_6(glval) = VariableAddress[x1] : +# 122| m122_7(int) = InitializeParameter[x1] : &:r122_6 +# 122| r122_8(glval) = VariableAddress[x2] : +# 122| m122_9(int) = InitializeParameter[x2] : &:r122_8 # 123| r123_1(glval) = VariableAddress[a] : # 123| mu123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -504,14 +479,14 @@ ssa.cpp: # 123| r123_7(int) = Constant[0] : # 123| mu123_8(int) = Store : &:r123_6, r123_7 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_6 +# 124| r124_2(bool) = Load : &:r124_1, m122_5 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_8 +# 125| r125_2(int) = Load : &:r125_1, m122_7 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| mu125_5(int) = Store : &:r125_4, r125_2 @@ -519,7 +494,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_10 +# 128| r128_2(int) = Load : &:r128_1, m122_9 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| mu128_5(int) = Store : &:r128_4, r128_2 @@ -529,30 +504,28 @@ ssa.cpp: # 130| r130_1(glval) = VariableAddress[x] : # 130| r130_2(glval) = VariableAddress[a] : # 130| r130_3(glval) = FieldAddress[x] : r130_2 -# 130| r130_4(int) = Load : &:r130_3, ~mu122_4 +# 130| r130_4(int) = Load : &:r130_3, ~m? # 130| m130_5(int) = Store : &:r130_1, r130_4 # 131| r131_1(glval) = VariableAddress[b] : # 131| r131_2(glval) = VariableAddress[a] : -# 131| r131_3(Point) = Load : &:r131_2, ~mu122_4 +# 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = UnmodeledUse : mu* -# 122| v122_13(void) = AliasedUse : ~mu122_4 -# 122| v122_14(void) = ExitFunction : +# 122| v122_10(void) = ReturnVoid : +# 122| v122_11(void) = AliasedUse : ~m? +# 122| v122_12(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 # 134| v134_1(void) = EnterFunction : # 134| mu134_2(unknown) = AliasedDefinition : # 134| mu134_3(unknown) = InitializeNonLocal : -# 134| mu134_4(unknown) = UnmodeledDefinition : -# 134| r134_5(glval) = VariableAddress[c] : -# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 -# 134| r134_7(glval) = VariableAddress[p] : -# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 -# 134| r134_9(glval) = VariableAddress[x1] : -# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 +# 134| r134_4(glval) = VariableAddress[c] : +# 134| m134_5(bool) = InitializeParameter[c] : &:r134_4 +# 134| r134_6(glval) = VariableAddress[p] : +# 134| m134_7(Point) = InitializeParameter[p] : &:r134_6 +# 134| r134_8(glval) = VariableAddress[x1] : +# 134| m134_9(int) = InitializeParameter[x1] : &:r134_8 # 135| r135_1(glval) = VariableAddress[a] : # 135| mu135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -562,14 +535,14 @@ ssa.cpp: # 135| r135_7(int) = Constant[0] : # 135| mu135_8(int) = Store : &:r135_6, r135_7 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_6 +# 136| r136_2(bool) = Load : &:r136_1, m134_5 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_10 +# 137| r137_2(int) = Load : &:r137_1, m134_9 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| mu137_5(int) = Store : &:r137_4, r137_2 @@ -577,7 +550,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_8 +# 140| r140_2(Point) = Load : &:r140_1, m134_7 # 140| r140_3(glval) = VariableAddress[a] : # 140| mu140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -586,26 +559,24 @@ ssa.cpp: # 142| r142_1(glval) = VariableAddress[x] : # 142| r142_2(glval) = VariableAddress[a] : # 142| r142_3(glval) = FieldAddress[x] : r142_2 -# 142| r142_4(int) = Load : &:r142_3, ~mu134_4 +# 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : -# 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = UnmodeledUse : mu* -# 134| v134_13(void) = AliasedUse : ~mu134_4 -# 134| v134_14(void) = ExitFunction : +# 134| v134_10(void) = ReturnVoid : +# 134| v134_11(void) = AliasedUse : ~m? +# 134| v134_12(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 # 145| v145_1(void) = EnterFunction : # 145| mu145_2(unknown) = AliasedDefinition : # 145| mu145_3(unknown) = InitializeNonLocal : -# 145| mu145_4(unknown) = UnmodeledDefinition : -# 145| r145_5(glval) = VariableAddress[c] : -# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 -# 145| r145_7(glval) = VariableAddress[p] : -# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 -# 145| r145_9(glval) = VariableAddress[x1] : -# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 +# 145| r145_4(glval) = VariableAddress[c] : +# 145| m145_5(bool) = InitializeParameter[c] : &:r145_4 +# 145| r145_6(glval) = VariableAddress[p] : +# 145| m145_7(Point) = InitializeParameter[p] : &:r145_6 +# 145| r145_8(glval) = VariableAddress[x1] : +# 145| m145_9(int) = InitializeParameter[x1] : &:r145_8 # 146| r146_1(glval) = VariableAddress[a] : # 146| mu146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -615,14 +586,14 @@ ssa.cpp: # 146| r146_7(int) = Constant[0] : # 146| mu146_8(int) = Store : &:r146_6, r146_7 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_6 +# 147| r147_2(bool) = Load : &:r147_1, m145_5 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_10 +# 148| r148_2(int) = Load : &:r148_1, m145_9 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| mu148_5(int) = Store : &:r148_4, r148_2 @@ -630,7 +601,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_8 +# 151| r151_2(Point) = Load : &:r151_1, m145_7 # 151| r151_3(glval) = VariableAddress[a] : # 151| mu151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -638,26 +609,24 @@ ssa.cpp: # 153| Block 3 # 153| r153_1(glval) = VariableAddress[b] : # 153| r153_2(glval) = VariableAddress[a] : -# 153| r153_3(Point) = Load : &:r153_2, ~mu145_4 +# 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : -# 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = UnmodeledUse : mu* -# 145| v145_13(void) = AliasedUse : ~mu145_4 -# 145| v145_14(void) = ExitFunction : +# 145| v145_10(void) = ReturnVoid : +# 145| v145_11(void) = AliasedUse : ~m? +# 145| v145_12(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 # 156| v156_1(void) = EnterFunction : # 156| mu156_2(unknown) = AliasedDefinition : # 156| mu156_3(unknown) = InitializeNonLocal : -# 156| mu156_4(unknown) = UnmodeledDefinition : -# 156| r156_5(glval) = VariableAddress[c] : -# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 -# 156| r156_7(glval) = VariableAddress[r] : -# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 -# 156| r156_9(glval) = VariableAddress[x1] : -# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 +# 156| r156_4(glval) = VariableAddress[c] : +# 156| m156_5(bool) = InitializeParameter[c] : &:r156_4 +# 156| r156_6(glval) = VariableAddress[r] : +# 156| m156_7(Rect) = InitializeParameter[r] : &:r156_6 +# 156| r156_8(glval) = VariableAddress[x1] : +# 156| m156_9(int) = InitializeParameter[x1] : &:r156_8 # 157| r157_1(glval) = VariableAddress[a] : # 157| mu157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -667,14 +636,14 @@ ssa.cpp: # 157| r157_7(Point) = Constant[0] : # 157| mu157_8(Point) = Store : &:r157_6, r157_7 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_6 +# 158| r158_2(bool) = Load : &:r158_1, m156_5 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_10 +# 159| r159_2(int) = Load : &:r159_1, m156_9 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -683,7 +652,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_8 +# 162| r162_2(Rect) = Load : &:r162_1, m156_7 # 162| r162_3(glval) = VariableAddress[a] : # 162| mu162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -692,30 +661,28 @@ ssa.cpp: # 164| r164_1(glval) = VariableAddress[b] : # 164| r164_2(glval) = VariableAddress[a] : # 164| r164_3(glval) = FieldAddress[topLeft] : r164_2 -# 164| r164_4(Point) = Load : &:r164_3, ~mu156_4 +# 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : -# 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = UnmodeledUse : mu* -# 156| v156_13(void) = AliasedUse : ~mu156_4 -# 156| v156_14(void) = ExitFunction : +# 156| v156_10(void) = ReturnVoid : +# 156| v156_11(void) = AliasedUse : ~m? +# 156| v156_12(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[w] : -# 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 +# 171| r171_4(glval) = VariableAddress[w] : +# 171| mu171_5(Wrapper) = InitializeParameter[w] : &:r171_4 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, ~mu171_4 +# 172| r172_3(Wrapper) = Load : &:r172_2, ~m? # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~mu171_4 +# 173| r173_4(int) = Load : &:r173_3, ~m? # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -723,128 +690,122 @@ ssa.cpp: # 174| mu174_4(int) = Store : &:r174_3, r174_1 # 175| r175_1(glval) = VariableAddress[w] : # 175| r175_2(glval) = FieldAddress[f] : r175_1 -# 175| r175_3(int) = Load : &:r175_2, ~mu171_4 +# 175| r175_3(int) = Load : &:r175_2, ~m? # 175| r175_4(glval) = VariableAddress[a] : # 175| m175_5(int) = Store : &:r175_4, r175_3 # 176| r176_1(glval) = VariableAddress[w] : -# 176| r176_2(Wrapper) = Load : &:r176_1, ~mu171_4 +# 176| r176_2(Wrapper) = Load : &:r176_1, ~m? # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = UnmodeledUse : mu* -# 171| v171_9(void) = AliasedUse : ~mu171_4 -# 171| v171_10(void) = ExitFunction : +# 171| v171_6(void) = ReturnVoid : +# 171| v171_7(void) = AliasedUse : ~m? +# 171| v171_8(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 # 179| v179_1(void) = EnterFunction : # 179| mu179_2(unknown) = AliasedDefinition : # 179| mu179_3(unknown) = InitializeNonLocal : -# 179| mu179_4(unknown) = UnmodeledDefinition : -# 179| r179_5(glval) = VariableAddress[p] : -# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 -# 179| r179_7(int *) = Load : &:r179_5, m179_6 -# 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 -# 180| mu180_1(unknown) = InlineAsm : ~mu179_4 +# 179| r179_4(glval) = VariableAddress[p] : +# 179| m179_5(int *) = InitializeParameter[p] : &:r179_4 +# 179| r179_6(int *) = Load : &:r179_4, m179_5 +# 179| mu179_7(unknown) = InitializeIndirection[p] : &:r179_6 +# 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_6 -# 181| r181_4(int) = Load : &:r181_3, ~mu179_4 +# 181| r181_3(int *) = Load : &:r181_2, m179_5 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 -# 179| r179_10(glval) = VariableAddress[#return] : -# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = UnmodeledUse : mu* -# 179| v179_13(void) = AliasedUse : ~mu179_4 -# 179| v179_14(void) = ExitFunction : +# 179| v179_8(void) = ReturnIndirection[p] : &:r179_6, ~m? +# 179| r179_9(glval) = VariableAddress[#return] : +# 179| v179_10(void) = ReturnValue : &:r179_9, m181_5 +# 179| v179_11(void) = AliasedUse : ~m? +# 179| v179_12(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 # 184| v184_1(void) = EnterFunction : # 184| mu184_2(unknown) = AliasedDefinition : # 184| mu184_3(unknown) = InitializeNonLocal : -# 184| mu184_4(unknown) = UnmodeledDefinition : -# 184| r184_5(glval) = VariableAddress[a] : -# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 -# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 -# 184| mu184_8(unknown) = InitializeIndirection[a] : &:r184_7 -# 184| r184_9(glval) = VariableAddress[b] : -# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 -# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 -# 184| mu184_12(unknown) = InitializeIndirection[b] : &:r184_11 -# 184| r184_13(glval) = VariableAddress[c] : -# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 -# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 -# 184| mu184_16(unknown) = InitializeIndirection[c] : &:r184_15 -# 184| r184_17(glval) = VariableAddress[d] : -# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 -# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 -# 184| mu184_20(unknown) = InitializeIndirection[d] : &:r184_19 +# 184| r184_4(glval) = VariableAddress[a] : +# 184| m184_5(unsigned int &) = InitializeParameter[a] : &:r184_4 +# 184| r184_6(unsigned int &) = Load : &:r184_4, m184_5 +# 184| mu184_7(unknown) = InitializeIndirection[a] : &:r184_6 +# 184| r184_8(glval) = VariableAddress[b] : +# 184| m184_9(unsigned int &) = InitializeParameter[b] : &:r184_8 +# 184| r184_10(unsigned int &) = Load : &:r184_8, m184_9 +# 184| mu184_11(unknown) = InitializeIndirection[b] : &:r184_10 +# 184| r184_12(glval) = VariableAddress[c] : +# 184| m184_13(unsigned int &) = InitializeParameter[c] : &:r184_12 +# 184| r184_14(unsigned int &) = Load : &:r184_12, m184_13 +# 184| mu184_15(unknown) = InitializeIndirection[c] : &:r184_14 +# 184| r184_16(glval) = VariableAddress[d] : +# 184| m184_17(unsigned int &) = InitializeParameter[d] : &:r184_16 +# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 +# 184| mu184_19(unknown) = InitializeIndirection[d] : &:r184_18 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_5 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_9 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~mu184_4 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_13 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~mu184_4 -# 186| mu186_1(unknown) = InlineAsm : ~mu184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_17 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m? +# 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 -# 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = UnmodeledUse : mu* -# 184| v184_27(void) = AliasedUse : ~mu184_4 -# 184| v184_28(void) = ExitFunction : +# 184| v184_20(void) = ReturnIndirection[a] : &:r184_6, ~m? +# 184| v184_21(void) = ReturnIndirection[b] : &:r184_10, ~m? +# 184| v184_22(void) = ReturnIndirection[c] : &:r184_14, ~m? +# 184| v184_23(void) = ReturnIndirection[d] : &:r184_18, ~m? +# 184| v184_24(void) = ReturnVoid : +# 184| v184_25(void) = AliasedUse : ~m? +# 184| v184_26(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 # 198| v198_1(void) = EnterFunction : # 198| mu198_2(unknown) = AliasedDefinition : # 198| mu198_3(unknown) = InitializeNonLocal : -# 198| mu198_4(unknown) = UnmodeledDefinition : -# 198| r198_5(glval) = VariableAddress[str1] : -# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 -# 198| r198_7(char *) = Load : &:r198_5, m198_6 -# 198| mu198_8(unknown) = InitializeIndirection[str1] : &:r198_7 -# 198| r198_9(glval) = VariableAddress[str2] : -# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 -# 198| r198_11(char *) = Load : &:r198_9, m198_10 -# 198| mu198_12(unknown) = InitializeIndirection[str2] : &:r198_11 -# 198| r198_13(glval) = VariableAddress[x] : -# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 +# 198| r198_4(glval) = VariableAddress[str1] : +# 198| m198_5(char *) = InitializeParameter[str1] : &:r198_4 +# 198| r198_6(char *) = Load : &:r198_4, m198_5 +# 198| mu198_7(unknown) = InitializeIndirection[str1] : &:r198_6 +# 198| r198_8(glval) = VariableAddress[str2] : +# 198| m198_9(char *) = InitializeParameter[str2] : &:r198_8 +# 198| r198_10(char *) = Load : &:r198_8, m198_9 +# 198| mu198_11(unknown) = InitializeIndirection[str2] : &:r198_10 +# 198| r198_12(glval) = VariableAddress[x] : +# 198| m198_13(int) = InitializeParameter[x] : &:r198_12 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_6 +# 199| r199_4(char *) = Load : &:r199_3, m198_5 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_10 +# 199| r199_7(char *) = Load : &:r199_6, m198_9 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m? # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_6 +# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_14 +# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -854,22 +815,20 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 -# 198| r198_17(glval) = VariableAddress[#return] : -# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = UnmodeledUse : mu* -# 198| v198_20(void) = AliasedUse : ~mu198_4 -# 198| v198_21(void) = ExitFunction : +# 198| v198_14(void) = ReturnIndirection[str1] : &:r198_6, ~m? +# 198| v198_15(void) = ReturnIndirection[str2] : &:r198_10, ~m? +# 198| r198_16(glval) = VariableAddress[#return] : +# 198| v198_17(void) = ReturnValue : &:r198_16, m202_4 +# 198| v198_18(void) = AliasedUse : ~m? +# 198| v198_19(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 # 207| v207_1(void) = EnterFunction : # 207| mu207_2(unknown) = AliasedDefinition : # 207| mu207_3(unknown) = InitializeNonLocal : -# 207| mu207_4(unknown) = UnmodeledDefinition : -# 207| r207_5(glval) = VariableAddress[x] : -# 207| mu207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| r207_4(glval) = VariableAddress[x] : +# 207| mu207_5(int) = InitializeParameter[x] : &:r207_4 # 208| r208_1(glval) = VariableAddress[y] : # 208| mu208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -881,35 +840,33 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~mu207_4 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m? # 209| mu209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : -# 210| r210_3(int) = Load : &:r210_2, ~mu207_4 +# 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_7(glval) = VariableAddress[#return] : -# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = UnmodeledUse : mu* -# 207| v207_10(void) = AliasedUse : ~mu207_4 -# 207| v207_11(void) = ExitFunction : +# 207| r207_6(glval) = VariableAddress[#return] : +# 207| v207_7(void) = ReturnValue : &:r207_6, m210_4 +# 207| v207_8(void) = AliasedUse : ~m? +# 207| v207_9(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 # 213| v213_1(void) = EnterFunction : # 213| mu213_2(unknown) = AliasedDefinition : # 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : -# 214| r214_3(char[32]) = Load : &:r214_2, ~mu213_4 +# 214| r214_3(char[32]) = Load : &:r214_2, ~m? # 214| m214_4(char[32]) = Store : &:r214_1, r214_3 # 215| r215_1(glval) = VariableAddress[a_nopad] : # 215| r215_2(glval) = StringConstant["foo"] : -# 215| r215_3(char[4]) = Load : &:r215_2, ~mu213_4 +# 215| r215_3(char[4]) = Load : &:r215_2, ~m? # 215| m215_4(char[4]) = Store : &:r215_1, r215_3 # 216| r216_1(glval) = VariableAddress[a_infer] : # 216| r216_2(glval) = StringConstant["blah"] : -# 216| r216_3(char[5]) = Load : &:r216_2, ~mu213_4 +# 216| r216_3(char[5]) = Load : &:r216_2, ~m? # 216| m216_4(char[5]) = Store : &:r216_1, r216_3 # 217| r217_1(glval) = VariableAddress[b] : # 217| m217_2(char[2]) = Uninitialized[b] : &:r217_1 @@ -950,20 +907,18 @@ ssa.cpp: # 221| r221_9(unknown[2]) = Constant[0] : # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 # 226| v226_1(void) = EnterFunction : # 226| mu226_2(unknown) = AliasedDefinition : # 226| mu226_3(unknown) = InitializeNonLocal : -# 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 -# 227| mu227_3(unknown) = ^CallSideEffect : ~mu226_4 +# 227| mu227_3(unknown) = ^CallSideEffect : ~m? # 229| r229_1(glval) = VariableAddress[s] : # 229| r229_2(glval) = StringConstant["Literal"] : # 229| r229_3(char *) = Convert : r229_2 @@ -973,113 +928,113 @@ ssa.cpp: # 230| r230_3(char *) = Load : &:r230_2, m229_4 # 230| r230_4(int) = Constant[2] : # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 -# 230| r230_6(char) = Load : &:r230_5, ~mu226_4 +# 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_5(glval) = VariableAddress[#return] : -# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = UnmodeledUse : mu* -# 226| v226_8(void) = AliasedUse : ~mu226_4 -# 226| v226_9(void) = ExitFunction : +# 226| r226_4(glval) = VariableAddress[#return] : +# 226| v226_5(void) = ReturnValue : &:r226_4, m230_7 +# 226| v226_6(void) = AliasedUse : ~m? +# 226| v226_7(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| mu235_2(unknown) = AliasedDefinition : -# 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = UnmodeledUse : mu* -# 235| v235_11(void) = AliasedUse : ~mu235_4 -# 235| v235_12(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| mu235_2(unknown) = AliasedDefinition : +# 235| mu235_3(unknown) = InitializeNonLocal : +# 235| r235_4(glval) = VariableAddress[#this] : +# 235| m235_5(glval) = InitializeParameter[#this] : &:r235_4 +# 235| r235_6(glval) = Load : &:r235_4, m235_5 +# 235| mu235_7(Constructible) = InitializeIndirection[#this] : &:r235_6 +# 235| r235_8(glval) = VariableAddress[x] : +# 235| m235_9(int) = InitializeParameter[x] : &:r235_8 +# 235| v235_10(void) = NoOp : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| mu236_4(unknown) = UnmodeledDefinition : -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = UnmodeledUse : mu* -# 236| v236_9(void) = AliasedUse : ~mu236_4 -# 236| v236_10(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = VariableAddress[#this] : +# 236| m236_5(glval) = InitializeParameter[#this] : &:r236_4 +# 236| r236_6(glval) = Load : &:r236_4, m236_5 +# 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 +# 236| v236_8(void) = NoOp : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| mu240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : # 240| r240_4(int) = Constant[1] : # 240| v240_5(void) = Call : func:r240_3, this:r240_1, 0:r240_4 -# 240| mu240_6(unknown) = ^CallSideEffect : ~mu239_4 +# 240| mu240_6(unknown) = ^CallSideEffect : ~m? # 240| mu240_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1 # 241| r241_1(glval) = VariableAddress[c] : # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call : func:r241_2, this:r241_1 -# 241| mu241_4(unknown) = ^CallSideEffect : ~mu239_4 -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~mu239_4 +# 241| mu241_4(unknown) = ^CallSideEffect : ~m? +# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call : func:r242_2, this:r242_1 -# 242| mu242_4(unknown) = ^CallSideEffect : ~mu239_4 -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~mu239_4 +# 242| mu242_4(unknown) = ^CallSideEffect : ~m? +# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 # 243| r243_3(glval) = FunctionAddress[Constructible] : # 243| r243_4(int) = Constant[2] : # 243| v243_5(void) = Call : func:r243_3, this:r243_1, 0:r243_4 -# 243| mu243_6(unknown) = ^CallSideEffect : ~mu239_4 +# 243| mu243_6(unknown) = ^CallSideEffect : ~m? # 243| mu243_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1 # 244| r244_1(glval) = VariableAddress[c2] : # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call : func:r244_2, this:r244_1 -# 244| mu244_4(unknown) = ^CallSideEffect : ~mu239_4 -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~mu239_4 +# 244| mu244_4(unknown) = ^CallSideEffect : ~m? +# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : -# 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = UnmodeledUse : mu* -# 239| v239_7(void) = AliasedUse : ~mu239_4 -# 239| v239_8(void) = ExitFunction : +# 239| v239_4(void) = ReturnVoid : +# 239| v239_5(void) = AliasedUse : ~m? +# 239| v239_6(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 # 247| v247_1(void) = EnterFunction : # 247| mu247_2(unknown) = AliasedDefinition : # 247| mu247_3(unknown) = InitializeNonLocal : -# 247| mu247_4(unknown) = UnmodeledDefinition : -# 247| r247_5(glval) = VariableAddress[src] : -# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 -# 247| r247_7(char *) = Load : &:r247_5, m247_6 -# 247| mu247_8(unknown) = InitializeIndirection[src] : &:r247_7 -# 247| r247_9(glval) = VariableAddress[size] : -# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 +# 247| r247_4(glval) = VariableAddress[src] : +# 247| m247_5(char *) = InitializeParameter[src] : &:r247_4 +# 247| r247_6(char *) = Load : &:r247_4, m247_5 +# 247| mu247_7(unknown) = InitializeIndirection[src] : &:r247_6 +# 247| r247_8(glval) = VariableAddress[size] : +# 247| m247_9(int) = InitializeParameter[size] : &:r247_8 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_10 +# 248| r248_4(int) = Load : &:r248_3, m247_9 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| mu248_9(unknown) = ^CallSideEffect : ~mu247_4 +# 248| mu248_9(unknown) = ^CallSideEffect : ~m? # 248| mu248_10(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| r248_11(char *) = Convert : r248_8 # 248| m248_12(char *) = Store : &:r248_1, r248_11 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_6 +# 249| r249_3(char *) = Load : &:r249_2, m247_5 # 249| r249_4(glval) = CopyValue : r249_3 # 249| mu249_5(char) = Store : &:r249_4, r249_1 # 250| r250_1(glval) = FunctionAddress[memcpy] : @@ -1087,34 +1042,32 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_12 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_6 +# 250| r250_6(char *) = Load : &:r250_5, m247_5 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_10 +# 250| r250_9(int) = Load : &:r250_8, m247_9 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 -# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~mu247_4 +# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 # 251| r251_1(glval) = VariableAddress[#return] : # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 -# 247| r247_12(glval) = VariableAddress[#return] : -# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = UnmodeledUse : mu* -# 247| v247_15(void) = AliasedUse : ~mu247_4 -# 247| v247_16(void) = ExitFunction : +# 247| v247_10(void) = ReturnIndirection[src] : &:r247_6, ~m? +# 247| r247_11(glval) = VariableAddress[#return] : +# 247| v247_12(void) = ReturnValue : &:r247_11, m251_4 +# 247| v247_13(void) = AliasedUse : ~m? +# 247| v247_14(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 # 254| v254_1(void) = EnterFunction : # 254| mu254_2(unknown) = AliasedDefinition : # 254| mu254_3(unknown) = InitializeNonLocal : -# 254| mu254_4(unknown) = UnmodeledDefinition : -# 254| r254_5(glval) = VariableAddress[b] : -# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 +# 254| r254_4(glval) = VariableAddress[b] : +# 254| m254_5(bool) = InitializeParameter[b] : &:r254_4 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_6 +# 255| r255_2(bool) = Load : &:r255_1, m254_5 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1122,13 +1075,13 @@ ssa.cpp: # 256| Block 1 # 256| r256_1(glval) = FunctionAddress[ExternalFunc] : # 256| v256_2(void) = Call : func:r256_1 -# 256| mu256_3(unknown) = ^CallSideEffect : ~mu254_4 +# 256| mu256_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 259| Block 2 # 259| r259_1(glval) = FunctionAddress[ExternalFunc] : # 259| v259_2(void) = Call : func:r259_1 -# 259| mu259_3(unknown) = ^CallSideEffect : ~mu254_4 +# 259| mu259_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 262| Block 3 @@ -1141,67 +1094,63 @@ ssa.cpp: # 263| r263_3(char *) = Load : &:r263_2, m262_4 # 263| r263_4(int) = Constant[2] : # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 -# 263| r263_6(char) = Load : &:r263_5, ~mu254_4 +# 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_7(glval) = VariableAddress[#return] : -# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = UnmodeledUse : mu* -# 254| v254_10(void) = AliasedUse : ~mu254_4 -# 254| v254_11(void) = ExitFunction : +# 254| r254_6(glval) = VariableAddress[#return] : +# 254| v254_7(void) = ReturnValue : &:r254_6, m263_7 +# 254| v254_8(void) = AliasedUse : ~m? +# 254| v254_9(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 # 268| v268_1(void) = EnterFunction : # 268| mu268_2(unknown) = AliasedDefinition : # 268| mu268_3(unknown) = InitializeNonLocal : -# 268| mu268_4(unknown) = UnmodeledDefinition : -# 268| r268_5(glval) = VariableAddress[s] : -# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 -# 268| r268_7(void *) = Load : &:r268_5, m268_6 -# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 -# 268| r268_9(glval) = VariableAddress[size] : -# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 268| r268_4(glval) = VariableAddress[s] : +# 268| m268_5(void *) = InitializeParameter[s] : &:r268_4 +# 268| r268_6(void *) = Load : &:r268_4, m268_5 +# 268| mu268_7(unknown) = InitializeIndirection[s] : &:r268_6 +# 268| r268_8(glval) = VariableAddress[size] : +# 268| m268_9(int) = InitializeParameter[size] : &:r268_8 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_4(int) = Load : &:r269_3, m268_9 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_8(void *) = Store : &:r269_1, r269_5 # 270| r270_1(glval) = FunctionAddress[memcpy] : # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_8 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_5(void *) = Load : &:r270_4, m268_5 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_7(int) = Load : &:r270_6, m268_9 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 -# 268| r268_12(glval) = VariableAddress[#return] : -# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = UnmodeledUse : mu* -# 268| v268_15(void) = AliasedUse : ~mu268_4 -# 268| v268_16(void) = ExitFunction : +# 268| v268_10(void) = ReturnIndirection[s] : &:r268_6, ~m? +# 268| r268_11(glval) = VariableAddress[#return] : +# 268| v268_12(void) = ReturnValue : &:r268_11, m271_4 +# 268| v268_13(void) = AliasedUse : ~m? +# 268| v268_14(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 # 275| v275_1(void) = EnterFunction : # 275| mu275_2(unknown) = AliasedDefinition : # 275| mu275_3(unknown) = InitializeNonLocal : -# 275| mu275_4(unknown) = UnmodeledDefinition : -# 275| r275_5(glval) = VariableAddress[c] : -# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 -# 275| r275_7(glval) = VariableAddress[p] : -# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 -# 275| r275_9(glval) = VariableAddress[x1] : -# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 +# 275| r275_4(glval) = VariableAddress[c] : +# 275| m275_5(bool) = InitializeParameter[c] : &:r275_4 +# 275| r275_6(glval) = VariableAddress[p] : +# 275| m275_7(Point) = InitializeParameter[p] : &:r275_6 +# 275| r275_8(glval) = VariableAddress[x1] : +# 275| m275_9(int) = InitializeParameter[x1] : &:r275_8 # 276| r276_1(glval) = VariableAddress[a] : # 276| mu276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1215,14 +1164,14 @@ ssa.cpp: # 277| r277_3(glval) = VariableAddress[pp] : # 277| mu277_4(Point *) = Store : &:r277_3, r277_2 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_6 +# 278| r278_2(bool) = Load : &:r278_1, m275_5 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_10 +# 279| r279_2(int) = Load : &:r279_1, m275_9 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| mu279_5(int) = Store : &:r279_4, r279_2 @@ -1232,73 +1181,77 @@ ssa.cpp: # 281| r281_1(glval) = VariableAddress[x] : # 281| r281_2(glval) = VariableAddress[a] : # 281| r281_3(glval) = FieldAddress[x] : r281_2 -# 281| r281_4(int) = Load : &:r281_3, ~mu275_4 +# 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : -# 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = UnmodeledUse : mu* -# 275| v275_13(void) = AliasedUse : ~mu275_4 -# 275| v275_14(void) = ExitFunction : +# 275| v275_10(void) = ReturnVoid : +# 275| v275_11(void) = AliasedUse : ~m? +# 275| v275_12(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| mu286_2(unknown) = AliasedDefinition : -# 286| mu286_3(unknown) = InitializeNonLocal : -# 286| mu286_4(unknown) = UnmodeledDefinition : -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = UnmodeledUse : mu* -# 286| v286_11(void) = AliasedUse : ~mu286_4 -# 286| v286_12(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| mu286_2(unknown) = AliasedDefinition : +# 286| mu286_3(unknown) = InitializeNonLocal : +# 286| r286_4(glval) = VariableAddress[#this] : +# 286| m286_5(glval) = InitializeParameter[#this] : &:r286_4 +# 286| r286_6(glval) = Load : &:r286_4, m286_5 +# 286| mu286_7(A) = InitializeIndirection[#this] : &:r286_6 +# 286| r286_8(glval) = VariableAddress[x] : +# 286| m286_9(int) = InitializeParameter[x] : &:r286_8 +# 286| v286_10(void) = NoOp : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| mu287_2(unknown) = AliasedDefinition : -# 287| mu287_3(unknown) = InitializeNonLocal : -# 287| mu287_4(unknown) = UnmodeledDefinition : -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = UnmodeledUse : mu* -# 287| v287_14(void) = AliasedUse : ~mu287_4 -# 287| v287_15(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| mu287_2(unknown) = AliasedDefinition : +# 287| mu287_3(unknown) = InitializeNonLocal : +# 287| r287_4(glval) = VariableAddress[#this] : +# 287| m287_5(glval) = InitializeParameter[#this] : &:r287_4 +# 287| r287_6(glval) = Load : &:r287_4, m287_5 +# 287| mu287_7(A) = InitializeIndirection[#this] : &:r287_6 +# 287| r287_8(glval) = VariableAddress[p#0] : +# 287| m287_9(A *) = InitializeParameter[p#0] : &:r287_8 +# 287| r287_10(A *) = Load : &:r287_8, m287_9 +# 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 +# 287| v287_12(void) = NoOp : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| mu288_4(unknown) = UnmodeledDefinition : -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = UnmodeledUse : mu* -# 288| v288_9(void) = AliasedUse : ~mu288_4 -# 288| v288_10(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = VariableAddress[#this] : +# 288| m288_5(glval) = InitializeParameter[#this] : &:r288_4 +# 288| r288_6(glval) = Load : &:r288_4, m288_5 +# 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 +# 288| v288_8(void) = NoOp : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 # 291| v291_1(void) = EnterFunction : # 291| mu291_2(unknown) = AliasedDefinition : # 291| mu291_3(unknown) = InitializeNonLocal : -# 291| mu291_4(unknown) = UnmodeledDefinition : -# 291| r291_5(glval) = VariableAddress[x] : -# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 +# 291| r291_4(glval) = VariableAddress[x] : +# 291| m291_5(int) = InitializeParameter[x] : &:r291_4 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : # 292| r292_4(void *) = Call : func:r292_2, 0:r292_3 -# 292| mu292_5(unknown) = ^CallSideEffect : ~mu291_4 +# 292| mu292_5(unknown) = ^CallSideEffect : ~m? # 292| mu292_6(unknown) = ^InitializeDynamicAllocation : &:r292_4 # 292| r292_7(Point *) = Convert : r292_4 # 292| m292_8(Point *) = Store : &:r292_1, r292_7 @@ -1306,7 +1259,7 @@ ssa.cpp: # 293| r293_2(glval) = FunctionAddress[operator new] : # 293| r293_3(unsigned long) = Constant[8] : # 293| r293_4(void *) = Call : func:r293_2, 0:r293_3 -# 293| mu293_5(unknown) = ^CallSideEffect : ~mu291_4 +# 293| mu293_5(unknown) = ^CallSideEffect : ~m? # 293| mu293_6(unknown) = ^InitializeDynamicAllocation : &:r293_4 # 293| r293_7(Point *) = Convert : r293_4 # 293| m293_8(Point *) = Store : &:r293_1, r293_7 @@ -1314,92 +1267,112 @@ ssa.cpp: # 294| r294_2(glval) = FunctionAddress[operator new] : # 294| r294_3(unsigned long) = Constant[4] : # 294| r294_4(void *) = Call : func:r294_2, 0:r294_3 -# 294| mu294_5(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_5(unknown) = ^CallSideEffect : ~m? # 294| mu294_6(unknown) = ^InitializeDynamicAllocation : &:r294_4 # 294| r294_7(A *) = Convert : r294_4 # 294| r294_8(glval) = FunctionAddress[A] : # 294| r294_9(glval) = FunctionAddress[operator new] : # 294| r294_10(unsigned long) = Constant[4] : # 294| r294_11(void *) = Call : func:r294_9, 0:r294_10 -# 294| mu294_12(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_12(unknown) = ^CallSideEffect : ~m? # 294| mu294_13(unknown) = ^InitializeDynamicAllocation : &:r294_11 # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : -# 294| r294_17(int) = Load : &:r294_16, m291_6 +# 294| r294_17(int) = Load : &:r294_16, m291_5 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 -# 294| mu294_19(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 # 294| v294_21(void) = Call : func:r294_8, this:r294_7, 0:r294_14 -# 294| mu294_22(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_22(unknown) = ^CallSideEffect : ~m? # 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7 -# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~mu291_4 +# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m? # 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14 # 294| r294_26(glval) = FieldAddress[i] : r294_7 -# 294| r294_27(int) = Load : &:r294_26, ~mu291_4 +# 294| r294_27(int) = Load : &:r294_26, ~m? # 294| m294_28(int) = Store : &:r294_1, r294_27 # 295| r295_1(glval) = VariableAddress[a] : # 295| r295_2(glval) = FunctionAddress[operator new] : # 295| r295_3(unsigned long) = Constant[4] : # 295| r295_4(void *) = Call : func:r295_2, 0:r295_3 -# 295| mu295_5(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_5(unknown) = ^CallSideEffect : ~m? # 295| mu295_6(unknown) = ^InitializeDynamicAllocation : &:r295_4 # 295| r295_7(A *) = Convert : r295_4 # 295| r295_8(glval) = FunctionAddress[A] : # 295| v295_9(void) = Call : func:r295_8, this:r295_7 -# 295| mu295_10(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_10(unknown) = ^CallSideEffect : ~m? # 295| mu295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_7 # 295| m295_12(A *) = Store : &:r295_1, r295_7 # 296| r296_1(glval) = VariableAddress[#return] : # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_8 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_7(glval) = VariableAddress[#return] : -# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = UnmodeledUse : mu* -# 291| v291_10(void) = AliasedUse : ~mu291_4 -# 291| v291_11(void) = ExitFunction : +# 291| r291_6(glval) = VariableAddress[#return] : +# 291| v291_7(void) = ReturnValue : &:r291_6, m296_4 +# 291| v291_8(void) = AliasedUse : ~m? +# 291| v291_9(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 # 301| v301_1(void) = EnterFunction : # 301| mu301_2(unknown) = AliasedDefinition : # 301| mu301_3(unknown) = InitializeNonLocal : -# 301| mu301_4(unknown) = UnmodeledDefinition : -# 301| r301_5(glval) = VariableAddress[argc] : -# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 -# 301| r301_7(glval) = VariableAddress[argv] : -# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 -# 301| r301_9(char **) = Load : &:r301_7, m301_8 -# 301| mu301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| r301_4(glval) = VariableAddress[argc] : +# 301| m301_5(int) = InitializeParameter[argc] : &:r301_4 +# 301| r301_6(glval) = VariableAddress[argv] : +# 301| m301_7(char **) = InitializeParameter[argv] : &:r301_6 +# 301| r301_8(char **) = Load : &:r301_6, m301_7 +# 301| mu301_9(unknown) = InitializeIndirection[argv] : &:r301_8 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_3(int) = Load : &:r302_2, m301_5 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 302| r302_5(char **) = Load : &:r302_4, m301_7 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| mu302_7(unknown) = ^CallSideEffect : ~mu301_4 -# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~mu301_4 +# 302| mu302_7(unknown) = ^CallSideEffect : ~m? +# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_6 +# 303| r303_3(int) = Load : &:r303_2, m301_5 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 303| r303_5(char **) = Load : &:r303_4, m301_7 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 -# 303| mu303_7(unknown) = ^CallSideEffect : ~mu301_4 -# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~mu301_4 +# 303| mu303_7(unknown) = ^CallSideEffect : ~m? +# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_8 -# 304| r304_4(char *) = Load : &:r304_3, ~mu301_4 -# 304| r304_5(char) = Load : &:r304_4, ~mu301_4 +# 304| r304_3(char **) = Load : &:r304_2, m301_7 +# 304| r304_4(char *) = Load : &:r304_3, ~m? +# 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 -# 301| r301_12(glval) = VariableAddress[#return] : -# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = UnmodeledUse : mu* -# 301| v301_15(void) = AliasedUse : ~mu301_4 -# 301| v301_16(void) = ExitFunction : +# 301| v301_10(void) = ReturnIndirection[argv] : &:r301_8, ~m? +# 301| r301_11(glval) = VariableAddress[#return] : +# 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 +# 301| v301_13(void) = AliasedUse : ~m? +# 301| v301_14(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| mu310_2(unknown) = AliasedDefinition : +# 310| mu310_3(unknown) = InitializeNonLocal : +# 310| r310_4(glval) = VariableAddress[#this] : +# 310| m310_5(glval) = InitializeParameter[#this] : &:r310_4 +# 310| r310_6(glval) = Load : &:r310_4, m310_5 +# 310| mu310_7(ThisAliasTest) = InitializeIndirection[#this] : &:r310_6 +# 310| r310_8(glval) = VariableAddress[arg] : +# 310| m310_9(int) = InitializeParameter[arg] : &:r310_8 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_9 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_5 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| mu311_6(int) = Store : &:r311_5, r311_2 +# 312| v312_1(void) = NoOp : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index b307db1cfc5..1d155eaf30d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -4,26 +4,25 @@ ssa.cpp: # 13| v13_1(void) = EnterFunction : # 13| mu13_2(unknown) = AliasedDefinition : # 13| mu13_3(unknown) = InitializeNonLocal : -# 13| mu13_4(unknown) = UnmodeledDefinition : -# 13| r13_5(glval) = VariableAddress[p] : -# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 -# 13| r13_7(Point *) = Load : &:r13_5, m13_6 -# 13| mu13_8(unknown) = InitializeIndirection[p] : &:r13_7 -# 13| r13_9(glval) = VariableAddress[which1] : -# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 -# 13| r13_11(glval) = VariableAddress[which2] : -# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 +# 13| r13_4(glval) = VariableAddress[p] : +# 13| m13_5(Point *) = InitializeParameter[p] : &:r13_4 +# 13| r13_6(Point *) = Load : &:r13_4, m13_5 +# 13| mu13_7(unknown) = InitializeIndirection[p] : &:r13_6 +# 13| r13_8(glval) = VariableAddress[which1] : +# 13| m13_9(bool) = InitializeParameter[which1] : &:r13_8 +# 13| r13_10(glval) = VariableAddress[which2] : +# 13| m13_11(bool) = InitializeParameter[which2] : &:r13_10 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_10 +# 14| r14_2(bool) = Load : &:r14_1, m13_9 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_6 +# 15| r15_2(Point *) = Load : &:r15_1, m13_5 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~mu13_4 +# 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| mu15_7(int) = Store : &:r15_3, r15_6 @@ -31,9 +30,9 @@ ssa.cpp: # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_6 +# 18| r18_2(Point *) = Load : &:r18_1, m13_5 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~mu13_4 +# 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| mu18_7(int) = Store : &:r18_3, r18_6 @@ -41,16 +40,16 @@ ssa.cpp: # 21| Block 3 # 21| r21_1(glval) = VariableAddress[which2] : -# 21| r21_2(bool) = Load : &:r21_1, m13_12 +# 21| r21_2(bool) = Load : &:r21_1, m13_11 # 21| v21_3(void) = ConditionalBranch : r21_2 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_6 +# 22| r22_2(Point *) = Load : &:r22_1, m13_5 # 22| r22_3(glval) = FieldAddress[x] : r22_2 -# 22| r22_4(int) = Load : &:r22_3, ~mu13_4 +# 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : # 22| r22_6(int) = Add : r22_4, r22_5 # 22| mu22_7(int) = Store : &:r22_3, r22_6 @@ -58,9 +57,9 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_6 +# 25| r25_2(Point *) = Load : &:r25_1, m13_5 # 25| r25_3(glval) = FieldAddress[y] : r25_2 -# 25| r25_4(int) = Load : &:r25_3, ~mu13_4 +# 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : # 25| r25_6(int) = Add : r25_4, r25_5 # 25| mu25_7(int) = Store : &:r25_3, r25_6 @@ -69,47 +68,43 @@ ssa.cpp: # 28| Block 6 # 28| r28_1(glval) = VariableAddress[#return] : # 28| r28_2(glval) = VariableAddress[p] : -# 28| r28_3(Point *) = Load : &:r28_2, m13_6 +# 28| r28_3(Point *) = Load : &:r28_2, m13_5 # 28| r28_4(glval) = FieldAddress[x] : r28_3 -# 28| r28_5(int) = Load : &:r28_4, ~mu13_4 +# 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : -# 28| r28_7(Point *) = Load : &:r28_6, m13_6 +# 28| r28_7(Point *) = Load : &:r28_6, m13_5 # 28| r28_8(glval) = FieldAddress[y] : r28_7 -# 28| r28_9(int) = Load : &:r28_8, ~mu13_4 +# 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 -# 13| r13_14(glval) = VariableAddress[#return] : -# 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = UnmodeledUse : mu* -# 13| v13_17(void) = AliasedUse : ~mu13_4 -# 13| v13_18(void) = ExitFunction : +# 13| v13_12(void) = ReturnIndirection[p] : &:r13_6, ~m? +# 13| r13_13(glval) = VariableAddress[#return] : +# 13| v13_14(void) = ReturnValue : &:r13_13, m28_11 +# 13| v13_15(void) = AliasedUse : ~m? +# 13| v13_16(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 # 31| v31_1(void) = EnterFunction : # 31| mu31_2(unknown) = AliasedDefinition : # 31| mu31_3(unknown) = InitializeNonLocal : -# 31| mu31_4(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_5(glval) = VariableAddress[#return] : -# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = UnmodeledUse : mu* -# 31| v31_8(void) = AliasedUse : ~mu31_4 -# 31| v31_9(void) = ExitFunction : +# 31| r31_4(glval) = VariableAddress[#return] : +# 31| v31_5(void) = ReturnValue : &:r31_4, m35_3 +# 31| v31_6(void) = AliasedUse : ~m? +# 31| v31_7(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 # 38| v38_1(void) = EnterFunction : # 38| mu38_2(unknown) = AliasedDefinition : # 38| mu38_3(unknown) = InitializeNonLocal : -# 38| mu38_4(unknown) = UnmodeledDefinition : -# 38| r38_5(glval) = VariableAddress[b] : -# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 +# 38| r38_4(glval) = VariableAddress[b] : +# 38| m38_5(bool) = InitializeParameter[b] : &:r38_4 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -117,18 +112,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_6 +# 41| r41_2(bool) = Load : &:r41_1, m38_5 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 5 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 -# 38| r38_8(glval) = VariableAddress[#return] : -# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = UnmodeledUse : mu* -# 38| v38_11(void) = AliasedUse : ~mu38_4 -# 38| v38_12(void) = ExitFunction : +# 38| m38_6(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 +# 38| r38_7(glval) = VariableAddress[#return] : +# 38| v38_8(void) = ReturnValue : &:r38_7, m38_6 +# 38| v38_9(void) = AliasedUse : ~m? +# 38| v38_10(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,20 +170,19 @@ ssa.cpp: # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| mu59_2(unknown) = AliasedDefinition : -# 59| mu59_3(unknown) = InitializeNonLocal : -# 59| mu59_4(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| mu59_2(unknown) = AliasedDefinition : +# 59| mu59_3(unknown) = InitializeNonLocal : +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -198,32 +191,30 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_5(glval) = VariableAddress[#return] : -# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = UnmodeledUse : mu* -# 59| v59_8(void) = AliasedUse : ~mu59_4 -# 59| v59_9(void) = ExitFunction : +# 59| r59_4(glval) = VariableAddress[#return] : +# 59| v59_5(void) = ReturnValue : &:r59_4, m65_4 +# 59| v59_6(void) = AliasedUse : ~m? +# 59| v59_7(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_8(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 # 68| v68_1(void) = EnterFunction : # 68| mu68_2(unknown) = AliasedDefinition : # 68| mu68_3(unknown) = InitializeNonLocal : -# 68| mu68_4(unknown) = UnmodeledDefinition : -# 68| r68_5(glval) = VariableAddress[n] : -# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 -# 68| r68_7(glval) = VariableAddress[p] : -# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 -# 68| r68_9(char *) = Load : &:r68_7, m68_8 -# 68| mu68_10(unknown) = InitializeIndirection[p] : &:r68_9 +# 68| r68_4(glval) = VariableAddress[n] : +# 68| m68_5(int) = InitializeParameter[n] : &:r68_4 +# 68| r68_6(glval) = VariableAddress[p] : +# 68| m68_7(char *) = InitializeParameter[p] : &:r68_6 +# 68| r68_8(char *) = Load : &:r68_6, m68_7 +# 68| mu68_9(unknown) = InitializeIndirection[p] : &:r68_8 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_7 +# 69| m69_1(char *) = Phi : from 0:m68_7, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_5, from 2:m69_7 # 69| r69_3(glval) = VariableAddress[n] : # 69| r69_4(int) = Load : &:r69_3, m69_2 # 69| r69_5(int) = Constant[1] : @@ -250,20 +241,18 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 -# 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = UnmodeledUse : mu* -# 68| v68_14(void) = AliasedUse : ~mu68_4 -# 68| v68_15(void) = ExitFunction : +# 68| v68_10(void) = ReturnIndirection[p] : &:r68_8, ~m? +# 68| v68_11(void) = ReturnVoid : +# 68| v68_12(void) = AliasedUse : ~m? +# 68| v68_13(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 # 75| v75_1(void) = EnterFunction : # 75| mu75_2(unknown) = AliasedDefinition : # 75| mu75_3(unknown) = InitializeNonLocal : -# 75| mu75_4(unknown) = UnmodeledDefinition : -# 75| r75_5(glval) = VariableAddress[b] : -# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 +# 75| r75_4(glval) = VariableAddress[b] : +# 75| m75_5(bool) = InitializeParameter[b] : &:r75_4 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -274,7 +263,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_6 +# 79| r79_2(bool) = Load : &:r79_1, m75_5 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -310,191 +299,177 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = UnmodeledUse : mu* -# 75| v75_9(void) = AliasedUse : ~mu75_4 -# 75| v75_10(void) = ExitFunction : +# 75| v75_6(void) = ReturnVoid : +# 75| v75_7(void) = AliasedUse : ~m? +# 75| v75_8(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 # 91| v91_1(void) = EnterFunction : # 91| mu91_2(unknown) = AliasedDefinition : # 91| mu91_3(unknown) = InitializeNonLocal : -# 91| mu91_4(unknown) = UnmodeledDefinition : -# 91| r91_5(glval) = VariableAddress[a] : -# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 +# 91| r91_4(glval) = VariableAddress[a] : +# 91| m91_5(Point) = InitializeParameter[a] : &:r91_4 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_6 +# 92| r92_3(Point) = Load : &:r92_2, m91_5 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : ~mu91_4 -# 91| v91_10(void) = ExitFunction : +# 91| v91_6(void) = ReturnVoid : +# 91| v91_7(void) = AliasedUse : ~m? +# 91| v91_8(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 # 95| v95_1(void) = EnterFunction : # 95| mu95_2(unknown) = AliasedDefinition : # 95| mu95_3(unknown) = InitializeNonLocal : -# 95| mu95_4(unknown) = UnmodeledDefinition : -# 95| r95_5(glval) = VariableAddress[a] : -# 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| r95_4(glval) = VariableAddress[a] : +# 95| mu95_5(Point) = InitializeParameter[a] : &:r95_4 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, ~mu95_4 +# 96| r96_3(Point) = Load : &:r96_2, ~m? # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| mu97_6(unknown) = ^CallSideEffect : ~mu95_4 -# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~mu95_4 +# 97| mu97_6(unknown) = ^CallSideEffect : ~m? +# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : -# 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = UnmodeledUse : mu* -# 95| v95_9(void) = AliasedUse : ~mu95_4 -# 95| v95_10(void) = ExitFunction : +# 95| v95_6(void) = ReturnVoid : +# 95| v95_7(void) = AliasedUse : ~m? +# 95| v95_8(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 # 100| v100_1(void) = EnterFunction : # 100| mu100_2(unknown) = AliasedDefinition : # 100| mu100_3(unknown) = InitializeNonLocal : -# 100| mu100_4(unknown) = UnmodeledDefinition : -# 100| r100_5(glval) = VariableAddress[a] : -# 100| mu100_6(Point) = InitializeParameter[a] : &:r100_5 +# 100| r100_4(glval) = VariableAddress[a] : +# 100| mu100_5(Point) = InitializeParameter[a] : &:r100_4 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~mu100_4 +# 101| r101_4(int) = Load : &:r101_3, ~m? # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~mu100_4 +# 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = UnmodeledUse : mu* -# 100| v100_9(void) = AliasedUse : ~mu100_4 -# 100| v100_10(void) = ExitFunction : +# 100| v100_6(void) = ReturnVoid : +# 100| v100_7(void) = AliasedUse : ~m? +# 100| v100_8(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 # 105| v105_1(void) = EnterFunction : # 105| mu105_2(unknown) = AliasedDefinition : # 105| mu105_3(unknown) = InitializeNonLocal : -# 105| mu105_4(unknown) = UnmodeledDefinition : -# 105| r105_5(glval) = VariableAddress[a] : -# 105| mu105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| r105_4(glval) = VariableAddress[a] : +# 105| mu105_5(Point) = InitializeParameter[a] : &:r105_4 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~mu105_4 +# 106| r106_4(int) = Load : &:r106_3, ~m? # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~mu105_4 +# 107| r107_4(int) = Load : &:r107_3, ~m? # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| mu108_6(unknown) = ^CallSideEffect : ~mu105_4 -# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~mu105_4 +# 108| mu108_6(unknown) = ^CallSideEffect : ~m? +# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : -# 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = UnmodeledUse : mu* -# 105| v105_9(void) = AliasedUse : ~mu105_4 -# 105| v105_10(void) = ExitFunction : +# 105| v105_6(void) = ReturnVoid : +# 105| v105_7(void) = AliasedUse : ~m? +# 105| v105_8(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 # 111| v111_1(void) = EnterFunction : # 111| mu111_2(unknown) = AliasedDefinition : # 111| mu111_3(unknown) = InitializeNonLocal : -# 111| mu111_4(unknown) = UnmodeledDefinition : -# 111| r111_5(glval) = VariableAddress[x] : -# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 -# 111| r111_7(glval) = VariableAddress[y] : -# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 +# 111| r111_4(glval) = VariableAddress[x] : +# 111| m111_5(int) = InitializeParameter[x] : &:r111_4 +# 111| r111_6(glval) = VariableAddress[y] : +# 111| m111_7(int) = InitializeParameter[y] : &:r111_6 # 112| r112_1(glval) = VariableAddress[a] : # 112| mu112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_6 +# 112| r112_5(int) = Load : &:r112_4, m111_5 # 112| mu112_6(int) = Store : &:r112_3, r112_5 # 112| r112_7(glval) = FieldAddress[y] : r112_1 # 112| r112_8(glval) = VariableAddress[y] : -# 112| r112_9(int) = Load : &:r112_8, m111_8 +# 112| r112_9(int) = Load : &:r112_8, m111_7 # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : -# 113| r113_3(Point) = Load : &:r113_2, ~mu111_4 +# 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = UnmodeledUse : mu* -# 111| v111_11(void) = AliasedUse : ~mu111_4 -# 111| v111_12(void) = ExitFunction : +# 111| v111_8(void) = ReturnVoid : +# 111| v111_9(void) = AliasedUse : ~m? +# 111| v111_10(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 # 116| v116_1(void) = EnterFunction : # 116| mu116_2(unknown) = AliasedDefinition : # 116| mu116_3(unknown) = InitializeNonLocal : -# 116| mu116_4(unknown) = UnmodeledDefinition : -# 116| r116_5(glval) = VariableAddress[x] : -# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 -# 116| r116_7(glval) = VariableAddress[y] : -# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 +# 116| r116_4(glval) = VariableAddress[x] : +# 116| m116_5(int) = InitializeParameter[x] : &:r116_4 +# 116| r116_6(glval) = VariableAddress[y] : +# 116| m116_7(int) = InitializeParameter[y] : &:r116_6 # 117| r117_1(glval) = VariableAddress[a] : # 117| mu117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_6 +# 117| r117_5(int) = Load : &:r117_4, m116_5 # 117| mu117_6(int) = Store : &:r117_3, r117_5 # 117| r117_7(glval) = FieldAddress[y] : r117_1 # 117| r117_8(glval) = VariableAddress[y] : -# 117| r117_9(int) = Load : &:r117_8, m116_8 +# 117| r117_9(int) = Load : &:r117_8, m116_7 # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : -# 118| r118_3(Point) = Load : &:r118_2, ~mu116_4 +# 118| r118_3(Point) = Load : &:r118_2, ~m? # 118| m118_4(Point) = Store : &:r118_1, r118_3 # 119| r119_1(glval) = FunctionAddress[Escape] : # 119| r119_2(glval) = VariableAddress[a] : # 119| r119_3(Point *) = CopyValue : r119_2 # 119| r119_4(void *) = Convert : r119_3 # 119| v119_5(void) = Call : func:r119_1, 0:r119_4 -# 119| mu119_6(unknown) = ^CallSideEffect : ~mu116_4 -# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~mu116_4 +# 119| mu119_6(unknown) = ^CallSideEffect : ~m? +# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : -# 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = UnmodeledUse : mu* -# 116| v116_11(void) = AliasedUse : ~mu116_4 -# 116| v116_12(void) = ExitFunction : +# 116| v116_8(void) = ReturnVoid : +# 116| v116_9(void) = AliasedUse : ~m? +# 116| v116_10(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 # 122| v122_1(void) = EnterFunction : # 122| mu122_2(unknown) = AliasedDefinition : # 122| mu122_3(unknown) = InitializeNonLocal : -# 122| mu122_4(unknown) = UnmodeledDefinition : -# 122| r122_5(glval) = VariableAddress[c] : -# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 -# 122| r122_7(glval) = VariableAddress[x1] : -# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 -# 122| r122_9(glval) = VariableAddress[x2] : -# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 +# 122| r122_4(glval) = VariableAddress[c] : +# 122| m122_5(bool) = InitializeParameter[c] : &:r122_4 +# 122| r122_6(glval) = VariableAddress[x1] : +# 122| m122_7(int) = InitializeParameter[x1] : &:r122_6 +# 122| r122_8(glval) = VariableAddress[x2] : +# 122| m122_9(int) = InitializeParameter[x2] : &:r122_8 # 123| r123_1(glval) = VariableAddress[a] : # 123| mu123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -504,14 +479,14 @@ ssa.cpp: # 123| r123_7(int) = Constant[0] : # 123| mu123_8(int) = Store : &:r123_6, r123_7 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_6 +# 124| r124_2(bool) = Load : &:r124_1, m122_5 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_8 +# 125| r125_2(int) = Load : &:r125_1, m122_7 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| mu125_5(int) = Store : &:r125_4, r125_2 @@ -519,7 +494,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_10 +# 128| r128_2(int) = Load : &:r128_1, m122_9 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| mu128_5(int) = Store : &:r128_4, r128_2 @@ -529,30 +504,28 @@ ssa.cpp: # 130| r130_1(glval) = VariableAddress[x] : # 130| r130_2(glval) = VariableAddress[a] : # 130| r130_3(glval) = FieldAddress[x] : r130_2 -# 130| r130_4(int) = Load : &:r130_3, ~mu122_4 +# 130| r130_4(int) = Load : &:r130_3, ~m? # 130| m130_5(int) = Store : &:r130_1, r130_4 # 131| r131_1(glval) = VariableAddress[b] : # 131| r131_2(glval) = VariableAddress[a] : -# 131| r131_3(Point) = Load : &:r131_2, ~mu122_4 +# 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = UnmodeledUse : mu* -# 122| v122_13(void) = AliasedUse : ~mu122_4 -# 122| v122_14(void) = ExitFunction : +# 122| v122_10(void) = ReturnVoid : +# 122| v122_11(void) = AliasedUse : ~m? +# 122| v122_12(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 # 134| v134_1(void) = EnterFunction : # 134| mu134_2(unknown) = AliasedDefinition : # 134| mu134_3(unknown) = InitializeNonLocal : -# 134| mu134_4(unknown) = UnmodeledDefinition : -# 134| r134_5(glval) = VariableAddress[c] : -# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 -# 134| r134_7(glval) = VariableAddress[p] : -# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 -# 134| r134_9(glval) = VariableAddress[x1] : -# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 +# 134| r134_4(glval) = VariableAddress[c] : +# 134| m134_5(bool) = InitializeParameter[c] : &:r134_4 +# 134| r134_6(glval) = VariableAddress[p] : +# 134| m134_7(Point) = InitializeParameter[p] : &:r134_6 +# 134| r134_8(glval) = VariableAddress[x1] : +# 134| m134_9(int) = InitializeParameter[x1] : &:r134_8 # 135| r135_1(glval) = VariableAddress[a] : # 135| mu135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -562,14 +535,14 @@ ssa.cpp: # 135| r135_7(int) = Constant[0] : # 135| mu135_8(int) = Store : &:r135_6, r135_7 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_6 +# 136| r136_2(bool) = Load : &:r136_1, m134_5 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_10 +# 137| r137_2(int) = Load : &:r137_1, m134_9 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| mu137_5(int) = Store : &:r137_4, r137_2 @@ -577,7 +550,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_8 +# 140| r140_2(Point) = Load : &:r140_1, m134_7 # 140| r140_3(glval) = VariableAddress[a] : # 140| mu140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -586,26 +559,24 @@ ssa.cpp: # 142| r142_1(glval) = VariableAddress[x] : # 142| r142_2(glval) = VariableAddress[a] : # 142| r142_3(glval) = FieldAddress[x] : r142_2 -# 142| r142_4(int) = Load : &:r142_3, ~mu134_4 +# 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : -# 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = UnmodeledUse : mu* -# 134| v134_13(void) = AliasedUse : ~mu134_4 -# 134| v134_14(void) = ExitFunction : +# 134| v134_10(void) = ReturnVoid : +# 134| v134_11(void) = AliasedUse : ~m? +# 134| v134_12(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 # 145| v145_1(void) = EnterFunction : # 145| mu145_2(unknown) = AliasedDefinition : # 145| mu145_3(unknown) = InitializeNonLocal : -# 145| mu145_4(unknown) = UnmodeledDefinition : -# 145| r145_5(glval) = VariableAddress[c] : -# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 -# 145| r145_7(glval) = VariableAddress[p] : -# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 -# 145| r145_9(glval) = VariableAddress[x1] : -# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 +# 145| r145_4(glval) = VariableAddress[c] : +# 145| m145_5(bool) = InitializeParameter[c] : &:r145_4 +# 145| r145_6(glval) = VariableAddress[p] : +# 145| m145_7(Point) = InitializeParameter[p] : &:r145_6 +# 145| r145_8(glval) = VariableAddress[x1] : +# 145| m145_9(int) = InitializeParameter[x1] : &:r145_8 # 146| r146_1(glval) = VariableAddress[a] : # 146| mu146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -615,14 +586,14 @@ ssa.cpp: # 146| r146_7(int) = Constant[0] : # 146| mu146_8(int) = Store : &:r146_6, r146_7 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_6 +# 147| r147_2(bool) = Load : &:r147_1, m145_5 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_10 +# 148| r148_2(int) = Load : &:r148_1, m145_9 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| mu148_5(int) = Store : &:r148_4, r148_2 @@ -630,7 +601,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_8 +# 151| r151_2(Point) = Load : &:r151_1, m145_7 # 151| r151_3(glval) = VariableAddress[a] : # 151| mu151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -638,26 +609,24 @@ ssa.cpp: # 153| Block 3 # 153| r153_1(glval) = VariableAddress[b] : # 153| r153_2(glval) = VariableAddress[a] : -# 153| r153_3(Point) = Load : &:r153_2, ~mu145_4 +# 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : -# 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = UnmodeledUse : mu* -# 145| v145_13(void) = AliasedUse : ~mu145_4 -# 145| v145_14(void) = ExitFunction : +# 145| v145_10(void) = ReturnVoid : +# 145| v145_11(void) = AliasedUse : ~m? +# 145| v145_12(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 # 156| v156_1(void) = EnterFunction : # 156| mu156_2(unknown) = AliasedDefinition : # 156| mu156_3(unknown) = InitializeNonLocal : -# 156| mu156_4(unknown) = UnmodeledDefinition : -# 156| r156_5(glval) = VariableAddress[c] : -# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 -# 156| r156_7(glval) = VariableAddress[r] : -# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 -# 156| r156_9(glval) = VariableAddress[x1] : -# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 +# 156| r156_4(glval) = VariableAddress[c] : +# 156| m156_5(bool) = InitializeParameter[c] : &:r156_4 +# 156| r156_6(glval) = VariableAddress[r] : +# 156| m156_7(Rect) = InitializeParameter[r] : &:r156_6 +# 156| r156_8(glval) = VariableAddress[x1] : +# 156| m156_9(int) = InitializeParameter[x1] : &:r156_8 # 157| r157_1(glval) = VariableAddress[a] : # 157| mu157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -667,14 +636,14 @@ ssa.cpp: # 157| r157_7(Point) = Constant[0] : # 157| mu157_8(Point) = Store : &:r157_6, r157_7 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_6 +# 158| r158_2(bool) = Load : &:r158_1, m156_5 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_10 +# 159| r159_2(int) = Load : &:r159_1, m156_9 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -683,7 +652,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_8 +# 162| r162_2(Rect) = Load : &:r162_1, m156_7 # 162| r162_3(glval) = VariableAddress[a] : # 162| mu162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -692,30 +661,28 @@ ssa.cpp: # 164| r164_1(glval) = VariableAddress[b] : # 164| r164_2(glval) = VariableAddress[a] : # 164| r164_3(glval) = FieldAddress[topLeft] : r164_2 -# 164| r164_4(Point) = Load : &:r164_3, ~mu156_4 +# 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : -# 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = UnmodeledUse : mu* -# 156| v156_13(void) = AliasedUse : ~mu156_4 -# 156| v156_14(void) = ExitFunction : +# 156| v156_10(void) = ReturnVoid : +# 156| v156_11(void) = AliasedUse : ~m? +# 156| v156_12(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[w] : -# 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 +# 171| r171_4(glval) = VariableAddress[w] : +# 171| mu171_5(Wrapper) = InitializeParameter[w] : &:r171_4 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, ~mu171_4 +# 172| r172_3(Wrapper) = Load : &:r172_2, ~m? # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~mu171_4 +# 173| r173_4(int) = Load : &:r173_3, ~m? # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -723,128 +690,122 @@ ssa.cpp: # 174| mu174_4(int) = Store : &:r174_3, r174_1 # 175| r175_1(glval) = VariableAddress[w] : # 175| r175_2(glval) = FieldAddress[f] : r175_1 -# 175| r175_3(int) = Load : &:r175_2, ~mu171_4 +# 175| r175_3(int) = Load : &:r175_2, ~m? # 175| r175_4(glval) = VariableAddress[a] : # 175| m175_5(int) = Store : &:r175_4, r175_3 # 176| r176_1(glval) = VariableAddress[w] : -# 176| r176_2(Wrapper) = Load : &:r176_1, ~mu171_4 +# 176| r176_2(Wrapper) = Load : &:r176_1, ~m? # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = UnmodeledUse : mu* -# 171| v171_9(void) = AliasedUse : ~mu171_4 -# 171| v171_10(void) = ExitFunction : +# 171| v171_6(void) = ReturnVoid : +# 171| v171_7(void) = AliasedUse : ~m? +# 171| v171_8(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 # 179| v179_1(void) = EnterFunction : # 179| mu179_2(unknown) = AliasedDefinition : # 179| mu179_3(unknown) = InitializeNonLocal : -# 179| mu179_4(unknown) = UnmodeledDefinition : -# 179| r179_5(glval) = VariableAddress[p] : -# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 -# 179| r179_7(int *) = Load : &:r179_5, m179_6 -# 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 -# 180| mu180_1(unknown) = InlineAsm : ~mu179_4 +# 179| r179_4(glval) = VariableAddress[p] : +# 179| m179_5(int *) = InitializeParameter[p] : &:r179_4 +# 179| r179_6(int *) = Load : &:r179_4, m179_5 +# 179| mu179_7(unknown) = InitializeIndirection[p] : &:r179_6 +# 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_6 -# 181| r181_4(int) = Load : &:r181_3, ~mu179_4 +# 181| r181_3(int *) = Load : &:r181_2, m179_5 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 -# 179| r179_10(glval) = VariableAddress[#return] : -# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = UnmodeledUse : mu* -# 179| v179_13(void) = AliasedUse : ~mu179_4 -# 179| v179_14(void) = ExitFunction : +# 179| v179_8(void) = ReturnIndirection[p] : &:r179_6, ~m? +# 179| r179_9(glval) = VariableAddress[#return] : +# 179| v179_10(void) = ReturnValue : &:r179_9, m181_5 +# 179| v179_11(void) = AliasedUse : ~m? +# 179| v179_12(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 # 184| v184_1(void) = EnterFunction : # 184| mu184_2(unknown) = AliasedDefinition : # 184| mu184_3(unknown) = InitializeNonLocal : -# 184| mu184_4(unknown) = UnmodeledDefinition : -# 184| r184_5(glval) = VariableAddress[a] : -# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 -# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 -# 184| mu184_8(unknown) = InitializeIndirection[a] : &:r184_7 -# 184| r184_9(glval) = VariableAddress[b] : -# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 -# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 -# 184| mu184_12(unknown) = InitializeIndirection[b] : &:r184_11 -# 184| r184_13(glval) = VariableAddress[c] : -# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 -# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 -# 184| mu184_16(unknown) = InitializeIndirection[c] : &:r184_15 -# 184| r184_17(glval) = VariableAddress[d] : -# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 -# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 -# 184| mu184_20(unknown) = InitializeIndirection[d] : &:r184_19 +# 184| r184_4(glval) = VariableAddress[a] : +# 184| m184_5(unsigned int &) = InitializeParameter[a] : &:r184_4 +# 184| r184_6(unsigned int &) = Load : &:r184_4, m184_5 +# 184| mu184_7(unknown) = InitializeIndirection[a] : &:r184_6 +# 184| r184_8(glval) = VariableAddress[b] : +# 184| m184_9(unsigned int &) = InitializeParameter[b] : &:r184_8 +# 184| r184_10(unsigned int &) = Load : &:r184_8, m184_9 +# 184| mu184_11(unknown) = InitializeIndirection[b] : &:r184_10 +# 184| r184_12(glval) = VariableAddress[c] : +# 184| m184_13(unsigned int &) = InitializeParameter[c] : &:r184_12 +# 184| r184_14(unsigned int &) = Load : &:r184_12, m184_13 +# 184| mu184_15(unknown) = InitializeIndirection[c] : &:r184_14 +# 184| r184_16(glval) = VariableAddress[d] : +# 184| m184_17(unsigned int &) = InitializeParameter[d] : &:r184_16 +# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 +# 184| mu184_19(unknown) = InitializeIndirection[d] : &:r184_18 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_5 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_9 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~mu184_4 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_13 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~mu184_4 -# 186| mu186_1(unknown) = InlineAsm : ~mu184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_17 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m? +# 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 -# 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = UnmodeledUse : mu* -# 184| v184_27(void) = AliasedUse : ~mu184_4 -# 184| v184_28(void) = ExitFunction : +# 184| v184_20(void) = ReturnIndirection[a] : &:r184_6, ~m? +# 184| v184_21(void) = ReturnIndirection[b] : &:r184_10, ~m? +# 184| v184_22(void) = ReturnIndirection[c] : &:r184_14, ~m? +# 184| v184_23(void) = ReturnIndirection[d] : &:r184_18, ~m? +# 184| v184_24(void) = ReturnVoid : +# 184| v184_25(void) = AliasedUse : ~m? +# 184| v184_26(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 # 198| v198_1(void) = EnterFunction : # 198| mu198_2(unknown) = AliasedDefinition : # 198| mu198_3(unknown) = InitializeNonLocal : -# 198| mu198_4(unknown) = UnmodeledDefinition : -# 198| r198_5(glval) = VariableAddress[str1] : -# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 -# 198| r198_7(char *) = Load : &:r198_5, m198_6 -# 198| mu198_8(unknown) = InitializeIndirection[str1] : &:r198_7 -# 198| r198_9(glval) = VariableAddress[str2] : -# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 -# 198| r198_11(char *) = Load : &:r198_9, m198_10 -# 198| mu198_12(unknown) = InitializeIndirection[str2] : &:r198_11 -# 198| r198_13(glval) = VariableAddress[x] : -# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 +# 198| r198_4(glval) = VariableAddress[str1] : +# 198| m198_5(char *) = InitializeParameter[str1] : &:r198_4 +# 198| r198_6(char *) = Load : &:r198_4, m198_5 +# 198| mu198_7(unknown) = InitializeIndirection[str1] : &:r198_6 +# 198| r198_8(glval) = VariableAddress[str2] : +# 198| m198_9(char *) = InitializeParameter[str2] : &:r198_8 +# 198| r198_10(char *) = Load : &:r198_8, m198_9 +# 198| mu198_11(unknown) = InitializeIndirection[str2] : &:r198_10 +# 198| r198_12(glval) = VariableAddress[x] : +# 198| m198_13(int) = InitializeParameter[x] : &:r198_12 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_6 +# 199| r199_4(char *) = Load : &:r199_3, m198_5 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_10 +# 199| r199_7(char *) = Load : &:r199_6, m198_9 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m? # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_6 +# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_14 +# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -854,22 +815,20 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 -# 198| r198_17(glval) = VariableAddress[#return] : -# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = UnmodeledUse : mu* -# 198| v198_20(void) = AliasedUse : ~mu198_4 -# 198| v198_21(void) = ExitFunction : +# 198| v198_14(void) = ReturnIndirection[str1] : &:r198_6, ~m? +# 198| v198_15(void) = ReturnIndirection[str2] : &:r198_10, ~m? +# 198| r198_16(glval) = VariableAddress[#return] : +# 198| v198_17(void) = ReturnValue : &:r198_16, m202_4 +# 198| v198_18(void) = AliasedUse : ~m? +# 198| v198_19(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 # 207| v207_1(void) = EnterFunction : # 207| mu207_2(unknown) = AliasedDefinition : # 207| mu207_3(unknown) = InitializeNonLocal : -# 207| mu207_4(unknown) = UnmodeledDefinition : -# 207| r207_5(glval) = VariableAddress[x] : -# 207| mu207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| r207_4(glval) = VariableAddress[x] : +# 207| mu207_5(int) = InitializeParameter[x] : &:r207_4 # 208| r208_1(glval) = VariableAddress[y] : # 208| mu208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -881,35 +840,33 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~mu207_4 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m? # 209| mu209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : -# 210| r210_3(int) = Load : &:r210_2, ~mu207_4 +# 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_7(glval) = VariableAddress[#return] : -# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = UnmodeledUse : mu* -# 207| v207_10(void) = AliasedUse : ~mu207_4 -# 207| v207_11(void) = ExitFunction : +# 207| r207_6(glval) = VariableAddress[#return] : +# 207| v207_7(void) = ReturnValue : &:r207_6, m210_4 +# 207| v207_8(void) = AliasedUse : ~m? +# 207| v207_9(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 # 213| v213_1(void) = EnterFunction : # 213| mu213_2(unknown) = AliasedDefinition : # 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : -# 214| r214_3(char[32]) = Load : &:r214_2, ~mu213_4 +# 214| r214_3(char[32]) = Load : &:r214_2, ~m? # 214| m214_4(char[32]) = Store : &:r214_1, r214_3 # 215| r215_1(glval) = VariableAddress[a_nopad] : # 215| r215_2(glval) = StringConstant["foo"] : -# 215| r215_3(char[4]) = Load : &:r215_2, ~mu213_4 +# 215| r215_3(char[4]) = Load : &:r215_2, ~m? # 215| m215_4(char[4]) = Store : &:r215_1, r215_3 # 216| r216_1(glval) = VariableAddress[a_infer] : # 216| r216_2(glval) = StringConstant["blah"] : -# 216| r216_3(char[5]) = Load : &:r216_2, ~mu213_4 +# 216| r216_3(char[5]) = Load : &:r216_2, ~m? # 216| m216_4(char[5]) = Store : &:r216_1, r216_3 # 217| r217_1(glval) = VariableAddress[b] : # 217| m217_2(char[2]) = Uninitialized[b] : &:r217_1 @@ -950,20 +907,18 @@ ssa.cpp: # 221| r221_9(unknown[2]) = Constant[0] : # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 # 226| v226_1(void) = EnterFunction : # 226| mu226_2(unknown) = AliasedDefinition : # 226| mu226_3(unknown) = InitializeNonLocal : -# 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 -# 227| mu227_3(unknown) = ^CallSideEffect : ~mu226_4 +# 227| mu227_3(unknown) = ^CallSideEffect : ~m? # 229| r229_1(glval) = VariableAddress[s] : # 229| r229_2(glval) = StringConstant["Literal"] : # 229| r229_3(char *) = Convert : r229_2 @@ -973,113 +928,113 @@ ssa.cpp: # 230| r230_3(char *) = Load : &:r230_2, m229_4 # 230| r230_4(int) = Constant[2] : # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 -# 230| r230_6(char) = Load : &:r230_5, ~mu226_4 +# 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_5(glval) = VariableAddress[#return] : -# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = UnmodeledUse : mu* -# 226| v226_8(void) = AliasedUse : ~mu226_4 -# 226| v226_9(void) = ExitFunction : +# 226| r226_4(glval) = VariableAddress[#return] : +# 226| v226_5(void) = ReturnValue : &:r226_4, m230_7 +# 226| v226_6(void) = AliasedUse : ~m? +# 226| v226_7(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| mu235_2(unknown) = AliasedDefinition : -# 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = UnmodeledUse : mu* -# 235| v235_11(void) = AliasedUse : ~mu235_4 -# 235| v235_12(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| mu235_2(unknown) = AliasedDefinition : +# 235| mu235_3(unknown) = InitializeNonLocal : +# 235| r235_4(glval) = VariableAddress[#this] : +# 235| m235_5(glval) = InitializeParameter[#this] : &:r235_4 +# 235| r235_6(glval) = Load : &:r235_4, m235_5 +# 235| mu235_7(Constructible) = InitializeIndirection[#this] : &:r235_6 +# 235| r235_8(glval) = VariableAddress[x] : +# 235| m235_9(int) = InitializeParameter[x] : &:r235_8 +# 235| v235_10(void) = NoOp : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| mu236_4(unknown) = UnmodeledDefinition : -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = UnmodeledUse : mu* -# 236| v236_9(void) = AliasedUse : ~mu236_4 -# 236| v236_10(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = VariableAddress[#this] : +# 236| m236_5(glval) = InitializeParameter[#this] : &:r236_4 +# 236| r236_6(glval) = Load : &:r236_4, m236_5 +# 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 +# 236| v236_8(void) = NoOp : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| mu240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : # 240| r240_4(int) = Constant[1] : # 240| v240_5(void) = Call : func:r240_3, this:r240_1, 0:r240_4 -# 240| mu240_6(unknown) = ^CallSideEffect : ~mu239_4 +# 240| mu240_6(unknown) = ^CallSideEffect : ~m? # 240| mu240_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1 # 241| r241_1(glval) = VariableAddress[c] : # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call : func:r241_2, this:r241_1 -# 241| mu241_4(unknown) = ^CallSideEffect : ~mu239_4 -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~mu239_4 +# 241| mu241_4(unknown) = ^CallSideEffect : ~m? +# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call : func:r242_2, this:r242_1 -# 242| mu242_4(unknown) = ^CallSideEffect : ~mu239_4 -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~mu239_4 +# 242| mu242_4(unknown) = ^CallSideEffect : ~m? +# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 # 243| r243_3(glval) = FunctionAddress[Constructible] : # 243| r243_4(int) = Constant[2] : # 243| v243_5(void) = Call : func:r243_3, this:r243_1, 0:r243_4 -# 243| mu243_6(unknown) = ^CallSideEffect : ~mu239_4 +# 243| mu243_6(unknown) = ^CallSideEffect : ~m? # 243| mu243_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1 # 244| r244_1(glval) = VariableAddress[c2] : # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call : func:r244_2, this:r244_1 -# 244| mu244_4(unknown) = ^CallSideEffect : ~mu239_4 -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~mu239_4 +# 244| mu244_4(unknown) = ^CallSideEffect : ~m? +# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : -# 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = UnmodeledUse : mu* -# 239| v239_7(void) = AliasedUse : ~mu239_4 -# 239| v239_8(void) = ExitFunction : +# 239| v239_4(void) = ReturnVoid : +# 239| v239_5(void) = AliasedUse : ~m? +# 239| v239_6(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 # 247| v247_1(void) = EnterFunction : # 247| mu247_2(unknown) = AliasedDefinition : # 247| mu247_3(unknown) = InitializeNonLocal : -# 247| mu247_4(unknown) = UnmodeledDefinition : -# 247| r247_5(glval) = VariableAddress[src] : -# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 -# 247| r247_7(char *) = Load : &:r247_5, m247_6 -# 247| mu247_8(unknown) = InitializeIndirection[src] : &:r247_7 -# 247| r247_9(glval) = VariableAddress[size] : -# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 +# 247| r247_4(glval) = VariableAddress[src] : +# 247| m247_5(char *) = InitializeParameter[src] : &:r247_4 +# 247| r247_6(char *) = Load : &:r247_4, m247_5 +# 247| mu247_7(unknown) = InitializeIndirection[src] : &:r247_6 +# 247| r247_8(glval) = VariableAddress[size] : +# 247| m247_9(int) = InitializeParameter[size] : &:r247_8 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_10 +# 248| r248_4(int) = Load : &:r248_3, m247_9 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| mu248_9(unknown) = ^CallSideEffect : ~mu247_4 +# 248| mu248_9(unknown) = ^CallSideEffect : ~m? # 248| mu248_10(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| r248_11(char *) = Convert : r248_8 # 248| m248_12(char *) = Store : &:r248_1, r248_11 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_6 +# 249| r249_3(char *) = Load : &:r249_2, m247_5 # 249| r249_4(glval) = CopyValue : r249_3 # 249| mu249_5(char) = Store : &:r249_4, r249_1 # 250| r250_1(glval) = FunctionAddress[memcpy] : @@ -1087,34 +1042,32 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_12 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_6 +# 250| r250_6(char *) = Load : &:r250_5, m247_5 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_10 +# 250| r250_9(int) = Load : &:r250_8, m247_9 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 -# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~mu247_4 +# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 # 251| r251_1(glval) = VariableAddress[#return] : # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 -# 247| r247_12(glval) = VariableAddress[#return] : -# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = UnmodeledUse : mu* -# 247| v247_15(void) = AliasedUse : ~mu247_4 -# 247| v247_16(void) = ExitFunction : +# 247| v247_10(void) = ReturnIndirection[src] : &:r247_6, ~m? +# 247| r247_11(glval) = VariableAddress[#return] : +# 247| v247_12(void) = ReturnValue : &:r247_11, m251_4 +# 247| v247_13(void) = AliasedUse : ~m? +# 247| v247_14(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 # 254| v254_1(void) = EnterFunction : # 254| mu254_2(unknown) = AliasedDefinition : # 254| mu254_3(unknown) = InitializeNonLocal : -# 254| mu254_4(unknown) = UnmodeledDefinition : -# 254| r254_5(glval) = VariableAddress[b] : -# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 +# 254| r254_4(glval) = VariableAddress[b] : +# 254| m254_5(bool) = InitializeParameter[b] : &:r254_4 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_6 +# 255| r255_2(bool) = Load : &:r255_1, m254_5 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1122,13 +1075,13 @@ ssa.cpp: # 256| Block 1 # 256| r256_1(glval) = FunctionAddress[ExternalFunc] : # 256| v256_2(void) = Call : func:r256_1 -# 256| mu256_3(unknown) = ^CallSideEffect : ~mu254_4 +# 256| mu256_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 259| Block 2 # 259| r259_1(glval) = FunctionAddress[ExternalFunc] : # 259| v259_2(void) = Call : func:r259_1 -# 259| mu259_3(unknown) = ^CallSideEffect : ~mu254_4 +# 259| mu259_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 262| Block 3 @@ -1141,67 +1094,63 @@ ssa.cpp: # 263| r263_3(char *) = Load : &:r263_2, m262_4 # 263| r263_4(int) = Constant[2] : # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 -# 263| r263_6(char) = Load : &:r263_5, ~mu254_4 +# 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_7(glval) = VariableAddress[#return] : -# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = UnmodeledUse : mu* -# 254| v254_10(void) = AliasedUse : ~mu254_4 -# 254| v254_11(void) = ExitFunction : +# 254| r254_6(glval) = VariableAddress[#return] : +# 254| v254_7(void) = ReturnValue : &:r254_6, m263_7 +# 254| v254_8(void) = AliasedUse : ~m? +# 254| v254_9(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 # 268| v268_1(void) = EnterFunction : # 268| mu268_2(unknown) = AliasedDefinition : # 268| mu268_3(unknown) = InitializeNonLocal : -# 268| mu268_4(unknown) = UnmodeledDefinition : -# 268| r268_5(glval) = VariableAddress[s] : -# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 -# 268| r268_7(void *) = Load : &:r268_5, m268_6 -# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 -# 268| r268_9(glval) = VariableAddress[size] : -# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 268| r268_4(glval) = VariableAddress[s] : +# 268| m268_5(void *) = InitializeParameter[s] : &:r268_4 +# 268| r268_6(void *) = Load : &:r268_4, m268_5 +# 268| mu268_7(unknown) = InitializeIndirection[s] : &:r268_6 +# 268| r268_8(glval) = VariableAddress[size] : +# 268| m268_9(int) = InitializeParameter[size] : &:r268_8 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_4(int) = Load : &:r269_3, m268_9 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_8(void *) = Store : &:r269_1, r269_5 # 270| r270_1(glval) = FunctionAddress[memcpy] : # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_8 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_5(void *) = Load : &:r270_4, m268_5 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_7(int) = Load : &:r270_6, m268_9 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 -# 268| r268_12(glval) = VariableAddress[#return] : -# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = UnmodeledUse : mu* -# 268| v268_15(void) = AliasedUse : ~mu268_4 -# 268| v268_16(void) = ExitFunction : +# 268| v268_10(void) = ReturnIndirection[s] : &:r268_6, ~m? +# 268| r268_11(glval) = VariableAddress[#return] : +# 268| v268_12(void) = ReturnValue : &:r268_11, m271_4 +# 268| v268_13(void) = AliasedUse : ~m? +# 268| v268_14(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 # 275| v275_1(void) = EnterFunction : # 275| mu275_2(unknown) = AliasedDefinition : # 275| mu275_3(unknown) = InitializeNonLocal : -# 275| mu275_4(unknown) = UnmodeledDefinition : -# 275| r275_5(glval) = VariableAddress[c] : -# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 -# 275| r275_7(glval) = VariableAddress[p] : -# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 -# 275| r275_9(glval) = VariableAddress[x1] : -# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 +# 275| r275_4(glval) = VariableAddress[c] : +# 275| m275_5(bool) = InitializeParameter[c] : &:r275_4 +# 275| r275_6(glval) = VariableAddress[p] : +# 275| m275_7(Point) = InitializeParameter[p] : &:r275_6 +# 275| r275_8(glval) = VariableAddress[x1] : +# 275| m275_9(int) = InitializeParameter[x1] : &:r275_8 # 276| r276_1(glval) = VariableAddress[a] : # 276| mu276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1215,14 +1164,14 @@ ssa.cpp: # 277| r277_3(glval) = VariableAddress[pp] : # 277| mu277_4(Point *) = Store : &:r277_3, r277_2 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_6 +# 278| r278_2(bool) = Load : &:r278_1, m275_5 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_10 +# 279| r279_2(int) = Load : &:r279_1, m275_9 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| mu279_5(int) = Store : &:r279_4, r279_2 @@ -1232,73 +1181,77 @@ ssa.cpp: # 281| r281_1(glval) = VariableAddress[x] : # 281| r281_2(glval) = VariableAddress[a] : # 281| r281_3(glval) = FieldAddress[x] : r281_2 -# 281| r281_4(int) = Load : &:r281_3, ~mu275_4 +# 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : -# 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = UnmodeledUse : mu* -# 275| v275_13(void) = AliasedUse : ~mu275_4 -# 275| v275_14(void) = ExitFunction : +# 275| v275_10(void) = ReturnVoid : +# 275| v275_11(void) = AliasedUse : ~m? +# 275| v275_12(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| mu286_2(unknown) = AliasedDefinition : -# 286| mu286_3(unknown) = InitializeNonLocal : -# 286| mu286_4(unknown) = UnmodeledDefinition : -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = UnmodeledUse : mu* -# 286| v286_11(void) = AliasedUse : ~mu286_4 -# 286| v286_12(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| mu286_2(unknown) = AliasedDefinition : +# 286| mu286_3(unknown) = InitializeNonLocal : +# 286| r286_4(glval) = VariableAddress[#this] : +# 286| m286_5(glval) = InitializeParameter[#this] : &:r286_4 +# 286| r286_6(glval) = Load : &:r286_4, m286_5 +# 286| mu286_7(A) = InitializeIndirection[#this] : &:r286_6 +# 286| r286_8(glval) = VariableAddress[x] : +# 286| m286_9(int) = InitializeParameter[x] : &:r286_8 +# 286| v286_10(void) = NoOp : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| mu287_2(unknown) = AliasedDefinition : -# 287| mu287_3(unknown) = InitializeNonLocal : -# 287| mu287_4(unknown) = UnmodeledDefinition : -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = UnmodeledUse : mu* -# 287| v287_14(void) = AliasedUse : ~mu287_4 -# 287| v287_15(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| mu287_2(unknown) = AliasedDefinition : +# 287| mu287_3(unknown) = InitializeNonLocal : +# 287| r287_4(glval) = VariableAddress[#this] : +# 287| m287_5(glval) = InitializeParameter[#this] : &:r287_4 +# 287| r287_6(glval) = Load : &:r287_4, m287_5 +# 287| mu287_7(A) = InitializeIndirection[#this] : &:r287_6 +# 287| r287_8(glval) = VariableAddress[p#0] : +# 287| m287_9(A *) = InitializeParameter[p#0] : &:r287_8 +# 287| r287_10(A *) = Load : &:r287_8, m287_9 +# 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 +# 287| v287_12(void) = NoOp : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| mu288_4(unknown) = UnmodeledDefinition : -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = UnmodeledUse : mu* -# 288| v288_9(void) = AliasedUse : ~mu288_4 -# 288| v288_10(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = VariableAddress[#this] : +# 288| m288_5(glval) = InitializeParameter[#this] : &:r288_4 +# 288| r288_6(glval) = Load : &:r288_4, m288_5 +# 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 +# 288| v288_8(void) = NoOp : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 # 291| v291_1(void) = EnterFunction : # 291| mu291_2(unknown) = AliasedDefinition : # 291| mu291_3(unknown) = InitializeNonLocal : -# 291| mu291_4(unknown) = UnmodeledDefinition : -# 291| r291_5(glval) = VariableAddress[x] : -# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 +# 291| r291_4(glval) = VariableAddress[x] : +# 291| m291_5(int) = InitializeParameter[x] : &:r291_4 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : # 292| r292_4(void *) = Call : func:r292_2, 0:r292_3 -# 292| mu292_5(unknown) = ^CallSideEffect : ~mu291_4 +# 292| mu292_5(unknown) = ^CallSideEffect : ~m? # 292| mu292_6(unknown) = ^InitializeDynamicAllocation : &:r292_4 # 292| r292_7(Point *) = Convert : r292_4 # 292| m292_8(Point *) = Store : &:r292_1, r292_7 @@ -1306,7 +1259,7 @@ ssa.cpp: # 293| r293_2(glval) = FunctionAddress[operator new] : # 293| r293_3(unsigned long) = Constant[8] : # 293| r293_4(void *) = Call : func:r293_2, 0:r293_3 -# 293| mu293_5(unknown) = ^CallSideEffect : ~mu291_4 +# 293| mu293_5(unknown) = ^CallSideEffect : ~m? # 293| mu293_6(unknown) = ^InitializeDynamicAllocation : &:r293_4 # 293| r293_7(Point *) = Convert : r293_4 # 293| m293_8(Point *) = Store : &:r293_1, r293_7 @@ -1314,92 +1267,112 @@ ssa.cpp: # 294| r294_2(glval) = FunctionAddress[operator new] : # 294| r294_3(unsigned long) = Constant[4] : # 294| r294_4(void *) = Call : func:r294_2, 0:r294_3 -# 294| mu294_5(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_5(unknown) = ^CallSideEffect : ~m? # 294| mu294_6(unknown) = ^InitializeDynamicAllocation : &:r294_4 # 294| r294_7(A *) = Convert : r294_4 # 294| r294_8(glval) = FunctionAddress[A] : # 294| r294_9(glval) = FunctionAddress[operator new] : # 294| r294_10(unsigned long) = Constant[4] : # 294| r294_11(void *) = Call : func:r294_9, 0:r294_10 -# 294| mu294_12(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_12(unknown) = ^CallSideEffect : ~m? # 294| mu294_13(unknown) = ^InitializeDynamicAllocation : &:r294_11 # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : -# 294| r294_17(int) = Load : &:r294_16, m291_6 +# 294| r294_17(int) = Load : &:r294_16, m291_5 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 -# 294| mu294_19(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 # 294| v294_21(void) = Call : func:r294_8, this:r294_7, 0:r294_14 -# 294| mu294_22(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_22(unknown) = ^CallSideEffect : ~m? # 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7 -# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~mu291_4 +# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m? # 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14 # 294| r294_26(glval) = FieldAddress[i] : r294_7 -# 294| r294_27(int) = Load : &:r294_26, ~mu291_4 +# 294| r294_27(int) = Load : &:r294_26, ~m? # 294| m294_28(int) = Store : &:r294_1, r294_27 # 295| r295_1(glval) = VariableAddress[a] : # 295| r295_2(glval) = FunctionAddress[operator new] : # 295| r295_3(unsigned long) = Constant[4] : # 295| r295_4(void *) = Call : func:r295_2, 0:r295_3 -# 295| mu295_5(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_5(unknown) = ^CallSideEffect : ~m? # 295| mu295_6(unknown) = ^InitializeDynamicAllocation : &:r295_4 # 295| r295_7(A *) = Convert : r295_4 # 295| r295_8(glval) = FunctionAddress[A] : # 295| v295_9(void) = Call : func:r295_8, this:r295_7 -# 295| mu295_10(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_10(unknown) = ^CallSideEffect : ~m? # 295| mu295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_7 # 295| m295_12(A *) = Store : &:r295_1, r295_7 # 296| r296_1(glval) = VariableAddress[#return] : # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_8 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_7(glval) = VariableAddress[#return] : -# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = UnmodeledUse : mu* -# 291| v291_10(void) = AliasedUse : ~mu291_4 -# 291| v291_11(void) = ExitFunction : +# 291| r291_6(glval) = VariableAddress[#return] : +# 291| v291_7(void) = ReturnValue : &:r291_6, m296_4 +# 291| v291_8(void) = AliasedUse : ~m? +# 291| v291_9(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 # 301| v301_1(void) = EnterFunction : # 301| mu301_2(unknown) = AliasedDefinition : # 301| mu301_3(unknown) = InitializeNonLocal : -# 301| mu301_4(unknown) = UnmodeledDefinition : -# 301| r301_5(glval) = VariableAddress[argc] : -# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 -# 301| r301_7(glval) = VariableAddress[argv] : -# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 -# 301| r301_9(char **) = Load : &:r301_7, m301_8 -# 301| mu301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| r301_4(glval) = VariableAddress[argc] : +# 301| m301_5(int) = InitializeParameter[argc] : &:r301_4 +# 301| r301_6(glval) = VariableAddress[argv] : +# 301| m301_7(char **) = InitializeParameter[argv] : &:r301_6 +# 301| r301_8(char **) = Load : &:r301_6, m301_7 +# 301| mu301_9(unknown) = InitializeIndirection[argv] : &:r301_8 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_3(int) = Load : &:r302_2, m301_5 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 302| r302_5(char **) = Load : &:r302_4, m301_7 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| mu302_7(unknown) = ^CallSideEffect : ~mu301_4 -# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~mu301_4 +# 302| mu302_7(unknown) = ^CallSideEffect : ~m? +# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_6 +# 303| r303_3(int) = Load : &:r303_2, m301_5 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 303| r303_5(char **) = Load : &:r303_4, m301_7 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 -# 303| mu303_7(unknown) = ^CallSideEffect : ~mu301_4 -# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~mu301_4 +# 303| mu303_7(unknown) = ^CallSideEffect : ~m? +# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_8 -# 304| r304_4(char *) = Load : &:r304_3, ~mu301_4 -# 304| r304_5(char) = Load : &:r304_4, ~mu301_4 +# 304| r304_3(char **) = Load : &:r304_2, m301_7 +# 304| r304_4(char *) = Load : &:r304_3, ~m? +# 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 -# 301| r301_12(glval) = VariableAddress[#return] : -# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = UnmodeledUse : mu* -# 301| v301_15(void) = AliasedUse : ~mu301_4 -# 301| v301_16(void) = ExitFunction : +# 301| v301_10(void) = ReturnIndirection[argv] : &:r301_8, ~m? +# 301| r301_11(glval) = VariableAddress[#return] : +# 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 +# 301| v301_13(void) = AliasedUse : ~m? +# 301| v301_14(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| mu310_2(unknown) = AliasedDefinition : +# 310| mu310_3(unknown) = InitializeNonLocal : +# 310| r310_4(glval) = VariableAddress[#this] : +# 310| m310_5(glval) = InitializeParameter[#this] : &:r310_4 +# 310| r310_6(glval) = Load : &:r310_4, m310_5 +# 310| mu310_7(ThisAliasTest) = InitializeIndirection[#this] : &:r310_6 +# 310| r310_8(glval) = VariableAddress[arg] : +# 310| m310_9(int) = InitializeParameter[arg] : &:r310_8 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_9 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_5 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| mu311_6(int) = Store : &:r311_5, r311_2 +# 312| v312_1(void) = NoOp : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql deleted file mode 100644 index c7d0ba957af..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected new file mode 100644 index 00000000000..21782bd5ef1 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected @@ -0,0 +1,3 @@ +multipleOperandMemoryLocations +missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql similarity index 89% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql index 120881bf018..97800ca6e80 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected new file mode 100644 index 00000000000..21782bd5ef1 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected @@ -0,0 +1,3 @@ +multipleOperandMemoryLocations +missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..fd03efbc267 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected deleted file mode 100644 index 7c2d1faf639..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.expected deleted file mode 100644 index 7c2d1faf639..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 18bf9212dbf..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/lambdas/captures/elements.expected b/cpp/ql/test/library-tests/lambdas/captures/elements.expected index 1720fa2ca8e..25bb695ea97 100644 --- a/cpp/ql/test/library-tests/lambdas/captures/elements.expected +++ b/cpp/ql/test/library-tests/lambdas/captures/elements.expected @@ -32,9 +32,13 @@ | captures.cpp:3:15:3:15 | definition of operator() | | captures.cpp:3:15:3:15 | operator() | | captures.cpp:3:15:5:5 | { ... } | +| captures.cpp:4:7:4:7 | (captured this) | | captures.cpp:4:7:4:7 | call to a | +| captures.cpp:4:7:4:7 | this | | captures.cpp:4:7:4:15 | ExprStmt | | captures.cpp:4:9:4:13 | ... + ... | +| captures.cpp:4:9:4:13 | this | +| captures.cpp:4:9:4:13 | x | | captures.cpp:4:13:4:13 | 1 | | captures.cpp:5:5:5:5 | return ... | | captures.cpp:6:3:6:3 | return ... | @@ -52,6 +56,8 @@ | captures.cpp:9:5:9:5 | definition of operator= | | captures.cpp:9:5:9:5 | operator= | | captures.cpp:9:5:11:5 | [...](...){...} | +| captures.cpp:9:5:11:5 | this | +| captures.cpp:9:5:11:5 | x | | captures.cpp:9:5:11:5 | {...} | | captures.cpp:9:5:11:6 | ExprStmt | | captures.cpp:9:9:9:9 | definition of operator() | @@ -59,13 +65,17 @@ | captures.cpp:9:9:11:5 | { ... } | | captures.cpp:10:7:10:7 | (captured this) | | captures.cpp:10:7:10:7 | (captured this) | +| captures.cpp:10:7:10:7 | (captured this) | | captures.cpp:10:7:10:7 | call to b | | captures.cpp:10:7:10:7 | definition of (captured this) | +| captures.cpp:10:7:10:7 | this | | captures.cpp:10:7:10:15 | ExprStmt | | captures.cpp:10:9:10:9 | definition of x | | captures.cpp:10:9:10:9 | x | | captures.cpp:10:9:10:9 | x | | captures.cpp:10:9:10:13 | ... + ... | +| captures.cpp:10:9:10:13 | this | +| captures.cpp:10:9:10:13 | x | | captures.cpp:10:13:10:13 | 1 | | captures.cpp:11:5:11:5 | return ... | | captures.cpp:12:3:12:3 | return ... | @@ -110,6 +120,7 @@ | captures.cpp:22:8:22:15 | myLambda | | captures.cpp:22:18:24:3 | [...](...){...} | | captures.cpp:22:18:24:3 | initializer for myLambda | +| captures.cpp:22:18:24:3 | y | | captures.cpp:22:18:24:3 | {...} | | captures.cpp:22:19:22:19 | (constructor) | | captures.cpp:22:19:22:19 | (constructor) | @@ -136,6 +147,10 @@ | captures.cpp:22:40:24:3 | { ... } | | captures.cpp:23:5:23:21 | return ... | | captures.cpp:23:12:23:16 | ... + ... | +| captures.cpp:23:12:23:16 | this | +| captures.cpp:23:12:23:16 | this | +| captures.cpp:23:12:23:16 | x | +| captures.cpp:23:12:23:16 | y | | captures.cpp:23:12:23:20 | ... + ... | | captures.cpp:23:16:23:16 | (reference dereference) | | captures.cpp:23:16:23:16 | definition of y | @@ -191,8 +206,6 @@ | end_pos.cpp:10:16:10:16 | 1 | | end_pos.cpp:12:1:12:1 | return ... | | file://:0:0:0:0 | | -| file://:0:0:0:0 | (captured this) | -| file://:0:0:0:0 | (captured this) | | file://:0:0:0:0 | (global namespace) | | file://:0:0:0:0 | (reference to) | | file://:0:0:0:0 | ..()(..) | @@ -218,8 +231,10 @@ | file://:0:0:0:0 | const lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 & | +| file://:0:0:0:0 | const lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 & | +| file://:0:0:0:0 | const lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 * | @@ -264,8 +279,10 @@ | file://:0:0:0:0 | lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 & | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 && | +| file://:0:0:0:0 | lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 & | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 && | +| file://:0:0:0:0 | lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 && | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 * | @@ -292,17 +309,4 @@ | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | reg_save_area | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | | file://:0:0:0:0 | void * | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | y | -| file://:0:0:0:0 | y | diff --git a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql index b369e26e5bc..bff506957b9 100644 --- a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql +++ b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql @@ -1,4 +1,4 @@ -import default +import cpp query predicate classUuids(Class cls, string uuid) { if exists(cls.getUuid()) then uuid = cls.getUuid() else uuid = "" diff --git a/cpp/ql/test/library-tests/members/this/test.cpp b/cpp/ql/test/library-tests/members/this/test.cpp new file mode 100644 index 00000000000..ae155e74845 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/test.cpp @@ -0,0 +1,129 @@ + +int global; + +class C { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } +}; + +// We want to test that D* is in the database even when there's no use of it, +// not even through an implicit dereference of `this`. +class D { + void f() { + global++; + } +}; + +template +class InstantiatedTemplateClass { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } +}; + +void instantiate() { + InstantiatedTemplateClass x; + x.f1(); + x.f2(); + x.f3(); + x.f4(); + x.f5(); + x.f6(); + x.f7(); + + float val = InstantiatedTemplateClass().f8(); +} + +// Since there are no instantiations of this class, we don't expect +// MemberFunction::getTypeOfThis() to hold. +template +class UninstantiatedTemplateClass { + int x; + +public: + + void f1() { + x++; + } +}; diff --git a/cpp/ql/test/library-tests/members/this/this.expected b/cpp/ql/test/library-tests/members/this/this.expected new file mode 100644 index 00000000000..d7f166e4898 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.expected @@ -0,0 +1,48 @@ +thisExprType +| test.cpp:11:5:11:5 | this | file://:0:0:0:0 | C * | +| test.cpp:16:5:16:8 | this | file://:0:0:0:0 | C * | +| test.cpp:21:12:21:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:26:12:26:12 | this | file://:0:0:0:0 | volatile C * | +| test.cpp:31:12:31:12 | this | file://:0:0:0:0 | const volatile C * | +| test.cpp:41:12:41:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:46:12:46:12 | this | file://:0:0:0:0 | C * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +#select +| test.cpp:9:8:9:9 | f1 | file://:0:0:0:0 | C * | +| test.cpp:14:8:14:9 | f2 | file://:0:0:0:0 | C * | +| test.cpp:19:7:19:8 | f3 | file://:0:0:0:0 | const C * | +| test.cpp:24:7:24:8 | f4 | file://:0:0:0:0 | volatile C * | +| test.cpp:29:7:29:8 | f5 | file://:0:0:0:0 | const volatile C * | +| test.cpp:34:8:34:9 | f6 | file://:0:0:0:0 | C * | +| test.cpp:39:9:39:10 | f7 | file://:0:0:0:0 | const C * | +| test.cpp:44:9:44:10 | f8 | file://:0:0:0:0 | C * | +| test.cpp:53:8:53:8 | f | file://:0:0:0:0 | D * | +| test.cpp:64:8:64:8 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:64:8:64:9 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:69:8:69:8 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:69:8:69:9 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:74:7:74:7 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:74:7:74:8 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:79:7:79:7 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:79:7:79:8 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:84:7:84:7 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:84:7:84:8 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:89:8:89:8 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:89:8:89:9 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:94:9:94:9 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:94:9:94:10 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:99:9:99:9 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:99:9:99:10 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass * | diff --git a/cpp/ql/test/library-tests/members/this/this.ql b/cpp/ql/test/library-tests/members/this/this.ql new file mode 100644 index 00000000000..b4ab73254d2 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.ql @@ -0,0 +1,6 @@ +import cpp + +query predicate thisExprType(ThisExpr e, Type t) { t = e.getType() } + +from MemberFunction f +select f, f.getTypeOfThis() diff --git a/cpp/ql/test/library-tests/range_based_for/range_based_for.expected b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected index 075acb19427..9dd78fd6010 100644 --- a/cpp/ql/test/library-tests/range_based_for/range_based_for.expected +++ b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected @@ -16,7 +16,7 @@ rangeVariables | test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__range) | file://:0:0:0:0 | const List & | conditions | test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | -| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | test.cpp:28:20:28:20 | (__begin) | test.cpp:28:20:28:20 | (__end) | | test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | beginVariables | test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__begin) | file://:0:0:0:0 | short * | @@ -28,5 +28,5 @@ endVariables | test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__end) | file://:0:0:0:0 | long * | updates | test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | -| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | file://:0:0:0:0 | (__begin) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | test.cpp:28:20:28:20 | (__begin) | | test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | diff --git a/cpp/ql/test/library-tests/security/encryption/test.cpp b/cpp/ql/test/library-tests/security/encryption/test.cpp new file mode 100644 index 00000000000..0e4f8292eb5 --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.cpp @@ -0,0 +1,12 @@ + +void des_function(); // insecure +void function_using_des(); // insecure +void EncryptWithDES(); // insecure + +void aes_function(); // secure +void function_using_aes(); // secure +void EncryptionWithAES(); // secure + +void abc_function(); +void function_using_abc(); +void EncryptionWithABC(); diff --git a/cpp/ql/test/library-tests/security/encryption/test.expected b/cpp/ql/test/library-tests/security/encryption/test.expected new file mode 100644 index 00000000000..a497544d029 --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.expected @@ -0,0 +1,9 @@ +| test.cpp:2:6:2:17 | des_function | getInsecureAlgorithmRegex | +| test.cpp:3:6:3:23 | function_using_des | getInsecureAlgorithmRegex | +| test.cpp:4:6:4:19 | EncryptWithDES | getInsecureAlgorithmRegex | +| test.cpp:6:6:6:17 | aes_function | getSecureAlgorithmRegex | +| test.cpp:7:6:7:23 | function_using_aes | getSecureAlgorithmRegex | +| test.cpp:8:6:8:22 | EncryptionWithAES | getSecureAlgorithmRegex | +| test.cpp:10:6:10:17 | abc_function | | +| test.cpp:11:6:11:23 | function_using_abc | | +| test.cpp:12:6:12:22 | EncryptionWithABC | | diff --git a/cpp/ql/test/library-tests/security/encryption/test.ql b/cpp/ql/test/library-tests/security/encryption/test.ql new file mode 100644 index 00000000000..6539611aa3a --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.ql @@ -0,0 +1,14 @@ +import default +import semmle.code.cpp.security.Encryption + +string describe(Function f) { + f.getName().regexpMatch(getSecureAlgorithmRegex()) and + result = "getSecureAlgorithmRegex" + or + f.getName().regexpMatch(getInsecureAlgorithmRegex()) and + result = "getInsecureAlgorithmRegex" +} + +from Function f +where exists(f.getLocation().getFile()) +select f, concat(describe(f), ", ") diff --git a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected index f21f75d8880..9da7f49698d 100644 --- a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected +++ b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected @@ -34,6 +34,7 @@ | exprs.cpp:7:10:7:16 | (reference to) | isPure | | | | exprs.cpp:7:11:7:15 | * ... | isPure | | | | exprs.cpp:7:12:7:15 | this | isPure | | | +| exprs.cpp:12:3:12:3 | this | isPure | | | | exprs.cpp:12:3:12:3 | v | isPure | | | | exprs.cpp:12:3:12:5 | ... -- | | mayBeImpure | mayBeGloballyImpure | | exprs.cpp:13:10:13:16 | (...) | isPure | | | @@ -70,4 +71,3 @@ | exprs.cpp:34:4:34:4 | t | isPure | | | | exprs.cpp:38:2:38:31 | call to myTemplateFunction | | mayBeImpure | mayBeGloballyImpure | | exprs.cpp:39:2:39:24 | call to myTemplateFunction | | mayBeImpure | mayBeGloballyImpure | -| file://:0:0:0:0 | this | isPure | | | diff --git a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected index 26c72b4e319..4930fdac720 100644 --- a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected +++ b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected @@ -62,6 +62,8 @@ | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public | @@ -69,6 +71,8 @@ | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern | diff --git a/cpp/ql/test/library-tests/static_cast/expr.expected b/cpp/ql/test/library-tests/static_cast/expr.expected index 7dc4465d718..19351c5da69 100644 --- a/cpp/ql/test/library-tests/static_cast/expr.expected +++ b/cpp/ql/test/library-tests/static_cast/expr.expected @@ -1,6 +1,6 @@ -| file://:0:0:0:0 | this | | ms.cpp:3:10:3:12 | 0 | | ms.cpp:3:10:3:12 | constructor init of field x | | ms.cpp:3:16:3:40 | static_cast... | +| ms.cpp:3:39:3:39 | this | | ms.cpp:3:39:3:39 | x | | ms.cpp:5:3:5:3 | call to S | diff --git a/cpp/ql/test/library-tests/synchronization/synchronization.expected b/cpp/ql/test/library-tests/synchronization/synchronization.expected index 323fd851cf4..e5a1b7f6dcb 100644 --- a/cpp/ql/test/library-tests/synchronization/synchronization.expected +++ b/cpp/ql/test/library-tests/synchronization/synchronization.expected @@ -19,9 +19,9 @@ | test.cpp:119:9:119:12 | call to lock | lockCall | test.cpp:119:3:119:6 | this | | test.cpp:119:9:119:12 | call to lock | mustlockCall | test.cpp:119:3:119:6 | this | | test.cpp:120:9:120:14 | call to unlock | unlockCall | test.cpp:120:3:120:6 | this | -| test.cpp:122:3:122:6 | call to lock | lockCall | file://:0:0:0:0 | this | -| test.cpp:122:3:122:6 | call to lock | mustlockCall | file://:0:0:0:0 | this | -| test.cpp:123:3:123:8 | call to unlock | unlockCall | file://:0:0:0:0 | this | +| test.cpp:122:3:122:6 | call to lock | lockCall | test.cpp:122:3:122:6 | this | +| test.cpp:122:3:122:6 | call to lock | mustlockCall | test.cpp:122:3:122:6 | this | +| test.cpp:123:3:123:8 | call to unlock | unlockCall | test.cpp:123:3:123:8 | this | | test.cpp:136:10:136:13 | call to lock | lockCall | test.cpp:136:3:136:7 | this8 | | test.cpp:136:10:136:13 | call to lock | mustlockCall | test.cpp:136:3:136:7 | this8 | | test.cpp:137:10:137:15 | call to unlock | unlockCall | test.cpp:137:3:137:7 | this8 | diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected new file mode 100644 index 00000000000..389b3a9496d --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected @@ -0,0 +1,120 @@ +missingOperand +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | Chi: vla_typedef | Instruction 'Chi: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +ambiguousSuccessors +| allocators.cpp:14:5:14:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes +missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected deleted file mode 100644 index e54fd26ba1c..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ /dev/null @@ -1,526 +0,0 @@ -missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| 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 | -| 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 | -ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes -missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 52963b455e2..3f9dcb1adf6 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -8,51 +8,22 @@ uniqueEnclosingCallable | misc.c:210:24:210:24 | 0 | Node should have one enclosing callable but has 0. | | misc.c:210:24:210:28 | ... + ... | Node should have one enclosing callable but has 0. | | misc.c:210:28:210:28 | 1 | Node should have one enclosing callable but has 0. | -uniqueTypeBound -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type bound but has 0. | -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type bound but has 0. | -uniqueTypeRepr -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type representation but has 0. | -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type representation but has 0. | +uniqueType uniqueNodeLocation | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | x | Node should have one location but has 4. | -| cpp11.cpp:82:17:82:55 | call to Val | Node should have one location but has 2. | -| cpp11.cpp:82:17:82:55 | call to Val | Node should have one location but has 2. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | | duff.c:2:12:2:12 | x | Node should have one location but has 4. | -| file://:0:0:0:0 | call to PolymorphicBase | Node should have one location but has 2. | -| file://:0:0:0:0 | call to PolymorphicDerived | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Val | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Val | Node should have one location but has 2. | -| file://:0:0:0:0 | call to exn1 | Node should have one location but has 2. | | file://:0:0:0:0 | p#2 | Node should have one location but has 0. | | file://:0:0:0:0 | p#2 | Node should have one location but has 0. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | -| ir.cpp:850:19:850:19 | call to PolymorphicBase | Node should have one location but has 2. | -| ir.cpp:851:22:851:22 | call to PolymorphicDerived | Node should have one location but has 2. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | x | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | x | Node should have one location but has 4. | -| try_catch.cpp:13:5:13:16 | call to exn1 | Node should have one location but has 2. | missingLocation | Nodes without location: 2 | uniqueNodeToString @@ -92,6 +63,10 @@ reverseRead storeIsPostUpdate argHasPostUpdate | builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:33:9:33:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:39:9:39:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:42:9:42:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | | cpp11.cpp:77:5:77:17 | unaryFunction | ArgumentNode is missing PostUpdateNode. | | destructors.cpp:52:14:52:16 | ref | ArgumentNode is missing PostUpdateNode. | | ir.cpp:623:5:623:5 | r | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 42ed7144f47..434d7c30127 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,61 +1,140 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| aggregateinitializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| aggregateinitializer.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| allocators.cpp:14:5:14:8 | Address | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedUse | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Chi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiPartial | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiTotal | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | EnterFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ExitFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | InitializeNonLocal | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Load | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ReturnValue | Node should have one location but has 4. | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition | Node should have one location but has 4. | -| allocators.cpp:14:5:14:8 | UnmodeledUse | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | SideEffect | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | VariableAddress | Node should have one location but has 4. | | array_delete.cpp:5:6:5:6 | AliasedDefinition | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | AliasedUse | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Chi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiPartial | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiTotal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | EnterFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ExitFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | InitializeNonLocal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ReturnVoid | Node should have one location but has 14. | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition | Node should have one location but has 14. | -| array_delete.cpp:5:6:5:6 | UnmodeledUse | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | SideEffect | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| assignexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | break_labels.c:2:5:2:5 | AliasedDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | AliasedUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Chi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiPartial | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiTotal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | EnterFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ExitFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | InitializeNonLocal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ReturnVoid | Node should have one location but has 20. | -| break_labels.c:2:5:2:5 | UnmodeledDefinition | Node should have one location but has 20. | -| break_labels.c:2:5:2:5 | UnmodeledUse | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | SideEffect | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Unreached | Node should have one location but has 20. | +| break_labels.c:2:11:2:11 | Address | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | VariableAddress | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | @@ -64,35 +143,56 @@ uniqueNodeLocation | conditional_destructors.cpp:29:6:29:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition | Node should have one location but has 2. | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledUse | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition | Node should have one location but has 2. | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledUse | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. | | constmemberaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | constmemberaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | constructorinitializer.cpp:3:9:3:9 | i | Node should have one location but has 2. | | constructorinitializer.cpp:3:9:3:9 | x | Node should have one location but has 2. | | constructorinitializer.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -100,89 +200,173 @@ uniqueNodeLocation | constructorinitializer.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledUse | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledUse | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| deleteexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | dostmt.c:8:6:8:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Chi | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:8:6:8:18 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:8:6:8:18 | UnmodeledUse | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Unreached | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Chi | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:16:6:16:18 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:16:6:16:18 | UnmodeledUse | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Unreached | Node should have one location but has 4. | | dostmt.c:25:6:25:18 | AliasedDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Chi | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiPartial | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiTotal | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | EnterFunction | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | InitializeNonLocal | Node should have one location but has 2. | -| dostmt.c:25:6:25:18 | UnmodeledDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Unreached | Node should have one location but has 2. | | dostmt.c:32:6:32:11 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | AliasedUse | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | Chi | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiTotal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | EnterFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ExitFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:32:6:32:11 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:32:6:32:11 | UnmodeledUse | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | SideEffect | Node should have one location but has 4. | | duff.c:2:6:2:6 | AliasedDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | AliasedUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Chi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiPartial | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiTotal | Node should have one location but has 20. | | duff.c:2:6:2:6 | EnterFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | ExitFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | InitializeNonLocal | Node should have one location but has 20. | | duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | | duff.c:2:6:2:6 | ReturnVoid | Node should have one location but has 20. | -| duff.c:2:6:2:6 | UnmodeledDefinition | Node should have one location but has 20. | -| duff.c:2:6:2:6 | UnmodeledUse | Node should have one location but has 20. | +| duff.c:2:6:2:6 | SideEffect | Node should have one location but has 20. | | duff.c:2:6:2:6 | Unreached | Node should have one location but has 20. | +| duff.c:2:12:2:12 | Address | Node should have one location but has 4. | | duff.c:2:12:2:12 | VariableAddress | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | @@ -191,61 +375,158 @@ uniqueNodeLocation | dummyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| dummyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| dummyblock.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| emptyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| emptyblock.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedUse | Node should have one location but has 20. | | enum.c:5:5:5:5 | Chi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiPartial | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiTotal | Node should have one location but has 20. | | enum.c:5:5:5:5 | EnterFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | ExitFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | InitializeNonLocal | Node should have one location but has 20. | | enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | | enum.c:5:5:5:5 | ReturnVoid | Node should have one location but has 20. | -| enum.c:5:5:5:5 | UnmodeledDefinition | Node should have one location but has 20. | -| enum.c:5:5:5:5 | UnmodeledUse | Node should have one location but has 20. | +| enum.c:5:5:5:5 | SideEffect | Node should have one location but has 20. | | enum.c:5:5:5:5 | Unreached | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| exprstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| exprstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | fieldaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | fieldaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| fieldaccess.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | -| file://:0:0:0:0 | InitializeIndirection | Node should have one location but has 0. | +| fieldaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | +| file://:0:0:0:0 | *p#2 | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. | +| file://:0:0:0:0 | SideEffect | Node should have one location but has 0. | | file://:0:0:0:0 | VariableAddress | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | @@ -276,201 +557,327 @@ uniqueNodeLocation | forstmt.cpp:1:6:1:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition | Node should have one location but has 2. | -| forstmt.cpp:1:6:1:7 | UnmodeledUse | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition | Node should have one location but has 2. | -| forstmt.cpp:8:6:8:7 | UnmodeledUse | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. | | ifelsestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifelsestmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ReturnVoid | Node should have one location but has 3. | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifelsestmt.c:11:6:11:19 | UnmodeledUse | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:19:6:19:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:19:6:19:18 | UnmodeledUse | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:29:6:29:18 | UnmodeledUse | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:37:6:37:11 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:37:6:37:11 | UnmodeledUse | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | SideEffect | Node should have one location but has 4. | +| ifelsestmt.c:37:17:37:17 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | +| ifelsestmt.c:37:24:37:24 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifstmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifstmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifstmt.c:8:6:8:19 | UnmodeledUse | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:14:6:14:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:14:6:14:18 | UnmodeledUse | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:21:6:21:18 | UnmodeledUse | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | Chi | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:27:6:27:11 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:27:6:27:11 | UnmodeledUse | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | SideEffect | Node should have one location but has 4. | +| ifstmt.c:27:17:27:17 | Address | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | +| ifstmt.c:27:24:27:24 | Address | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | initializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | initializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| initializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| initializer.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| landexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| landexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| lorexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| lorexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| ltrbinopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| ltrbinopexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | membercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| membercallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | membercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | membercallexpr_args.cpp:4:14:4:14 | x | Node should have one location but has 2. | | membercallexpr_args.cpp:4:21:4:21 | y | Node should have one location but has 2. | | membercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledUse | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | | newexpr.cpp:3:9:3:9 | i | Node should have one location but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one location but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -478,36 +885,82 @@ uniqueNodeLocation | newexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| newexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | +| no_dynamic_init.cpp:9:5:9:8 | Address | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Chi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiPartial | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiTotal | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | EnterFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ExitFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Load | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ReturnValue | Node should have one location but has 4. | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition | Node should have one location but has 4. | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledUse | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | SideEffect | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| nodefaultswitchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nodefaultswitchstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -516,144 +969,328 @@ uniqueNodeLocation | nonmembercallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | nonmembercallexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | -| nonmembercallexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmembercallexpr.c:3:6:3:6 | UnmodeledUse | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | -| nonmemberfp2callexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmemberfp2callexpr.c:3:6:3:6 | UnmodeledUse | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| nonmemberfpcallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmemberfpcallexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| parameterinitializer.cpp:18:5:18:8 | Address | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedUse | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Chi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiPartial | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiTotal | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | EnterFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ExitFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Load | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ReturnValue | Node should have one location but has 4. | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition | Node should have one location but has 4. | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledUse | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | SideEffect | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | VariableAddress | Node should have one location but has 4. | | pmcallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | questionexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| questionexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| questionexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | revsubscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:21:4:21 | x | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:28:4:28 | y | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledUse | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | +| stream_it.cpp:16:5:16:8 | Address | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Chi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiPartial | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiTotal | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | EnterFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ExitFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | InitializeNonLocal | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Load | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ReturnValue | Node should have one location but has 4. | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition | Node should have one location but has 4. | -| stream_it.cpp:16:5:16:8 | UnmodeledUse | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | SideEffect | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | VariableAddress | Node should have one location but has 4. | | subscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| subscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| subscriptexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| switchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| switchstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| switchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -662,82 +1299,126 @@ uniqueNodeLocation | tinyforstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| tinyforstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| tinyforstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| unaryopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| unaryopexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | whilestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| whilestmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | -| whilestmt.c:8:6:8:19 | UnmodeledUse | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:15:6:15:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:15:6:15:18 | UnmodeledUse | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:23:6:23:18 | UnmodeledUse | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:32:6:32:18 | AliasedDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Chi | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiPartial | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiTotal | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | EnterFunction | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | InitializeNonLocal | Node should have one location but has 2. | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Unreached | Node should have one location but has 2. | | whilestmt.c:39:6:39:11 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | Chi | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:39:6:39:11 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:39:6:39:11 | UnmodeledUse | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | SideEffect | Node should have one location but has 4. | missingLocation -| Nodes without location: 30 | +| Nodes without location: 36 | uniqueNodeToString | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | @@ -761,8 +1442,6 @@ uniqueNodeToString | duff.c:3:14:3:14 | x | Node should have one toString but has 2. | | duff.c:4:13:4:13 | i | Node should have one toString but has 2. | | duff.c:4:13:4:13 | x | Node should have one toString but has 2. | -| ir.cpp:888:6:888:16 | (no string representation) | Node should have one toString but has 0. | -| misc.c:197:6:197:9 | (no string representation) | Node should have one toString but has 0. | | newexpr.cpp:3:9:3:9 | i | Node should have one toString but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one toString but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one toString but has 2. | @@ -780,7 +1459,6 @@ uniqueNodeToString | switchstmt.c:2:14:2:14 | i | Node should have one toString but has 2. | | switchstmt.c:2:14:2:14 | x | Node should have one toString but has 2. | missingToString -| Nodes without toString: 2 | parameterCallable localFlowIsLocal compatibleTypesReflexive @@ -790,7 +1468,7 @@ postIsNotPre postHasUniquePre | assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | | bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| file://:0:0:0:0 | Store | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | | ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected new file mode 100644 index 00000000000..61da658e201 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -0,0 +1,175 @@ +missingOperand +| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | +| 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 | int assign_designated_init(someStruct*) | 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 | int assign_designated_init(someStruct*) | 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 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | Instruction 'Load: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | Instruction 'IndirectMayWriteSideEffect: bi' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| enum.c:6:9:6:9 | Constant: (int)... | Instruction 'Constant: (int)...' has no successors in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:171:15:171:31 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:14:173:26 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:37:173:39 | Store: array to pointer conversion | Instruction 'Store: array to pointer conversion' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:221:10:221:10 | Store: 1 | Instruction 'Store: 1' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:222:10:222:10 | Store: 2 | Instruction 'Store: 2' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:9:19:9:19 | Load: j | Instruction 'Load: j' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | Instruction 'Sub: ... - ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | Instruction 'NoOp: { ... }' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | stmt_in_type.cpp:2:6:2:12 | void cpp_fun() | void cpp_fun() | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:16:5:19 | Load: argc | Instruction 'Load: argc' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | Instruction 'BufferReadSideEffect: (const char *)...' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:33:12:44 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:50:12:62 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:13:12:13:14 | Uninitialized: definition of var | Instruction 'Uninitialized: definition of var' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:36:14:47 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:53:14:65 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:74:14:79 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:92:14:94 | Store: (char *)... | Instruction 'Store: (char *)...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +ambiguousSuccessors +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +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 | void CallDestructor(int, int*) | void CallDestructor(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 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() | +| 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 | void throw_from_nonstmt(int) | 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 | int main(int, char**) | int main(int, char**) | +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes +missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref new file mode 100644 index 00000000000..eb7cc77b316 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected deleted file mode 100644 index 1ba36c90051..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ /dev/null @@ -1,582 +0,0 @@ -missingOperand -| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | -| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | -| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | -| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| 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*) | -| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | -| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| enum.c:6:9:6:9 | Constant: (int)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:171:15:171:31 | Add: ... + ... | -| misc.c:173:14:173:26 | Mul: ... * ... | -| misc.c:173:37:173:39 | Store: array to pointer conversion | -| misc.c:174:17:174:22 | CallSideEffect: call to getInt | -| misc.c:174:30:174:35 | CallSideEffect: call to getInt | -| misc.c:174:55:174:60 | Store: (char ****)... | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| misc.c:221:10:221:10 | Store: 1 | -| misc.c:222:10:222:10 | Store: 2 | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | -| ms_try_except.cpp:9:19:9:19 | Load: j | -| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | -| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | -| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | -| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | -| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | -| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | -| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | -| 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: { ... } | -| 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 | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:5:16:5:19 | Load: argc | -| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | -| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | -| vla.c:12:33:12:44 | Add: ... + ... | -| vla.c:12:50:12:62 | Mul: ... * ... | -| vla.c:13:12:13:14 | Uninitialized: definition of var | -| vla.c:14:36:14:47 | Add: ... + ... | -| vla.c:14:53:14:65 | Mul: ... * ... | -| vla.c:14:74:14:79 | CallSideEffect: call to getInt | -| vla.c:14:92:14:94 | Store: (char *)... | -ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -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*) | -| 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*) | -| 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 -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes -missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref deleted file mode 100644 index 959b466103c..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected new file mode 100644 index 00000000000..4307483dfee --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected @@ -0,0 +1,120 @@ +missingOperand +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +ambiguousSuccessors +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes +missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected deleted file mode 100644 index f70bf724111..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ /dev/null @@ -1,526 +0,0 @@ -missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| 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 | -| 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 | -ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes -missingCppType diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected index fbb93e657fe..5f066a7e4fd 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -54,6 +54,7 @@ | file://:0:0:0:0 | char8_t | | file://:0:0:0:0 | char16_t | | file://:0:0:0:0 | char32_t | +| file://:0:0:0:0 | composite * | | file://:0:0:0:0 | composite & | | file://:0:0:0:0 | composite && | | file://:0:0:0:0 | composite * | @@ -156,6 +157,7 @@ | file://:0:0:0:0 | restrict | | file://:0:0:0:0 | rule & | | file://:0:0:0:0 | rule && | +| file://:0:0:0:0 | rule * | | file://:0:0:0:0 | sealed | | file://:0:0:0:0 | selectany | | file://:0:0:0:0 | short | @@ -166,10 +168,6 @@ | file://:0:0:0:0 | signed long long | | file://:0:0:0:0 | signed short | | file://:0:0:0:0 | static | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | | file://:0:0:0:0 | thread | | file://:0:0:0:0 | unaligned | | file://:0:0:0:0 | unknown | @@ -230,6 +228,8 @@ | header.h:10:9:10:24 | composite:: | | header.h:10:9:10:28 | call to eval | | header.h:10:9:10:28 | call to eval | +| header.h:10:9:10:28 | this | +| header.h:10:9:10:28 | this | | header.h:10:9:10:32 | ExprStmt | | header.h:10:9:10:32 | ExprStmt | | header.h:10:30:10:30 | i | @@ -313,6 +313,8 @@ | test.cpp:18:13:18:16 | valx | | test.cpp:19:9:19:13 | actor | | test.cpp:19:9:19:13 | actor | +| test.cpp:19:9:19:13 | this | +| test.cpp:19:9:19:13 | this | | test.cpp:19:9:19:24 | call to expression | | test.cpp:19:9:19:25 | ExprStmt | | test.cpp:19:9:19:25 | ExprStmt | diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql index 3a34cc2ca1b..454f901fe38 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql @@ -2,7 +2,7 @@ import cpp class FunctionMonkeyPatch extends Function { language[monotonicAggregates] - override string toString() { + override string getDescription() { exists(string name, string templateArgs, string args | result = name + templateArgs + args and name = this.getQualifiedName() and @@ -30,7 +30,9 @@ class FunctionMonkeyPatch extends Function { } class ParameterMonkeyPatch extends Parameter { - override string toString() { result = super.getType().getName() + " " + super.toString() } + override string getDescription() { + result = super.getType().getName() + " " + super.getDescription() + } } from Element e, Element ti diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected index b5b562f95eb..d1e3cb3de15 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected @@ -6,8 +6,6 @@ isFromUninstantiatedTemplate | file://:0:0:0:0 | initializer for MyClassEnumConst | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass | | file://:0:0:0:0 | p#0 | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer | | file://:0:0:0:0 | p#0 | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer | -| file://:0:0:0:0 | this | load.cpp:13:7:13:27 | basic_text_iprimitive | -| file://:0:0:0:0 | this | load.cpp:22:10:22:13 | load | | isfromtemplateinstantiation.cpp:12:24:12:46 | definition of inner_template_function | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | | isfromtemplateinstantiation.cpp:13:1:17:1 | { ... } | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | @@ -222,6 +220,8 @@ isFromUninstantiatedTemplate | load.cpp:24:9:24:10 | (reference dereference) | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:10 | is | load.cpp:13:7:13:27 | basic_text_iprimitive | | load.cpp:24:9:24:10 | is | load.cpp:22:10:22:13 | load | +| load.cpp:24:9:24:10 | this | load.cpp:13:7:13:27 | basic_text_iprimitive | +| load.cpp:24:9:24:10 | this | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:15 | ... >> ... | load.cpp:13:7:13:27 | basic_text_iprimitive | | load.cpp:24:9:24:15 | ... >> ... | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:16 | ExprStmt | load.cpp:13:7:13:27 | basic_text_iprimitive | @@ -506,6 +506,7 @@ isFromUninstantiatedTemplate | load.cpp:22:19:22:19 | t | I | T | Declaration | | | load.cpp:24:9:24:10 | (reference dereference) | | T | Expr | | | load.cpp:24:9:24:10 | is | | T | Expr | Not ref | +| load.cpp:24:9:24:10 | this | | T | Expr | | | load.cpp:24:15:24:15 | (reference dereference) | | T | Expr | | | load.cpp:24:15:24:15 | t | | T | Expr | Not ref | | load.cpp:27:10:27:13 | load | | T | Declaration | | diff --git a/cpp/ql/test/library-tests/typename/typename.expected b/cpp/ql/test/library-tests/typename/typename.expected index 31a76b90ab2..87effb21662 100644 --- a/cpp/ql/test/library-tests/typename/typename.expected +++ b/cpp/ql/test/library-tests/typename/typename.expected @@ -1,4 +1,4 @@ -| file://:0:0:0:0 | T | -| file://:0:0:0:0 | int | -| file://:0:0:0:0 | myClass | -| file://:0:0:0:0 | short | +| typename.cpp:11:9:11:19 | T | +| typename.cpp:11:9:11:19 | short | +| typename.cpp:16:9:16:21 | int | +| typename.cpp:16:25:16:57 | myClass | diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.ql b/cpp/ql/test/library-tests/using-aliases/using-alias.ql index 79287777e4b..65a628996be 100644 --- a/cpp/ql/test/library-tests/using-aliases/using-alias.ql +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.ql @@ -1,4 +1,4 @@ import cpp from TypedefType t -select t, t.getCanonicalQLClass(), t.getUnderlyingType() +select t, t.getAPrimaryQlClass(), t.getUnderlyingType() diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 29fc4ebd652..c29cf7dd11f 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using c | -| usings.cpp:8:1:8:11 | using nf | -| usings.cpp:9:1:9:17 | using namespace N | -| usings.cpp:18:3:18:13 | using bf | -| usings.cpp:21:5:21:14 | using gf | -| usings.cpp:34:3:34:20 | using tbf | -| usings.cpp:42:5:42:22 | using foo | +| templates.cpp:9:5:9:14 | using c | UsingDeclarationEntry, enclosingElement:std | +| usings.cpp:8:1:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) | +| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) | +| usings.cpp:18:3:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D | +| usings.cpp:21:5:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } | +| usings.cpp:34:3:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD | +| usings.cpp:42:5:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings1.ql b/cpp/ql/test/library-tests/usings/Usings1.ql index 5e374a82059..2011c196571 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.ql +++ b/cpp/ql/test/library-tests/usings/Usings1.ql @@ -1,4 +1,14 @@ import cpp +string describe(UsingEntry ue) { + ue instanceof UsingDeclarationEntry and + result = "UsingDeclarationEntry" + or + ue instanceof UsingDirectiveEntry and + result = "UsingDirectiveEntry" + or + result = "enclosingElement:" + ue.getEnclosingElement().toString() +} + from UsingEntry ue -select ue +select ue, concat(describe(ue), ", ") diff --git a/cpp/ql/test/library-tests/usings/Usings2.expected b/cpp/ql/test/library-tests/usings/Usings2.expected deleted file mode 100644 index bb23b50e41a..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.expected +++ /dev/null @@ -1,7 +0,0 @@ -| templates.cpp:9:5:9:14 | using c | file://:0:0:0:0 | std | -| usings.cpp:8:1:8:11 | using nf | file://:0:0:0:0 | (global namespace) | -| usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) | -| usings.cpp:18:3:18:13 | using bf | usings.cpp:16:8:16:8 | D | -| usings.cpp:21:5:21:14 | using gf | usings.cpp:20:13:23:3 | { ... } | -| usings.cpp:34:3:34:20 | using tbf | usings.cpp:32:8:32:9 | TD | -| usings.cpp:42:5:42:22 | using foo | usings.cpp:41:11:41:15 | nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings2.ql b/cpp/ql/test/library-tests/usings/Usings2.ql deleted file mode 100644 index bc4a076b0c5..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.ql +++ /dev/null @@ -1,5 +0,0 @@ -import cpp - -from UsingEntry ue, Element e -where e = ue.getEnclosingElement() -select ue, e diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index 54982a6bc37..b5d59659460 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -8,16 +8,14 @@ test.cpp: # 1| valnum = unique # 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3 # 1| valnum = unique -# 1| mu1_5(unknown) = UnmodeledDefinition : -# 1| valnum = unique -# 1| r1_6(glval) = VariableAddress[p0] : -# 1| valnum = r1_6, r5_1, r6_1 -# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 -# 1| valnum = m1_7, r5_2, r6_2 -# 1| r1_8(glval) = VariableAddress[p1] : -# 1| valnum = r1_8, r5_3, r6_3 -# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 -# 1| valnum = m1_9, r5_4, r6_4 +# 1| r1_5(glval) = VariableAddress[p0] : +# 1| valnum = r1_5, r5_1, r6_1 +# 1| m1_6(int) = InitializeParameter[p0] : &:r1_5 +# 1| valnum = m1_6, r5_2, r6_2 +# 1| r1_7(glval) = VariableAddress[p1] : +# 1| valnum = r1_7, r5_3, r6_3 +# 1| m1_8(int) = InitializeParameter[p1] : &:r1_7 +# 1| valnum = m1_8, r5_4, r6_4 # 2| r2_1(glval) = VariableAddress[x] : # 2| valnum = r2_1, r5_6, r6_6, r7_1 # 2| m2_2(int) = Uninitialized[x] : &:r2_1 @@ -31,13 +29,13 @@ test.cpp: # 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1 # 3| valnum = unique # 5| r5_1(glval) = VariableAddress[p0] : -# 5| valnum = r1_6, r5_1, r6_1 -# 5| r5_2(int) = Load : &:r5_1, m1_7 -# 5| valnum = m1_7, r5_2, r6_2 +# 5| valnum = r1_5, r5_1, r6_1 +# 5| r5_2(int) = Load : &:r5_1, m1_6 +# 5| valnum = m1_6, r5_2, r6_2 # 5| r5_3(glval) = VariableAddress[p1] : -# 5| valnum = r1_8, r5_3, r6_3 -# 5| r5_4(int) = Load : &:r5_3, m1_9 -# 5| valnum = m1_9, r5_4, r6_4 +# 5| valnum = r1_7, r5_3, r6_3 +# 5| r5_4(int) = Load : &:r5_3, m1_8 +# 5| valnum = m1_8, r5_4, r6_4 # 5| r5_5(int) = Add : r5_2, r5_4 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 5| r5_6(glval) = VariableAddress[x] : @@ -45,13 +43,13 @@ test.cpp: # 5| m5_7(int) = Store : &:r5_6, r5_5 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 6| r6_1(glval) = VariableAddress[p0] : -# 6| valnum = r1_6, r5_1, r6_1 -# 6| r6_2(int) = Load : &:r6_1, m1_7 -# 6| valnum = m1_7, r5_2, r6_2 +# 6| valnum = r1_5, r5_1, r6_1 +# 6| r6_2(int) = Load : &:r6_1, m1_6 +# 6| valnum = m1_6, r5_2, r6_2 # 6| r6_3(glval) = VariableAddress[p1] : -# 6| valnum = r1_8, r5_3, r6_3 -# 6| r6_4(int) = Load : &:r6_3, m1_9 -# 6| valnum = m1_9, r5_4, r6_4 +# 6| valnum = r1_7, r5_3, r6_3 +# 6| r6_4(int) = Load : &:r6_3, m1_8 +# 6| valnum = m1_8, r5_4, r6_4 # 6| r6_5(int) = Add : r6_2, r6_4 # 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 6| r6_6(glval) = VariableAddress[x] : @@ -67,10 +65,9 @@ test.cpp: # 7| m7_4(int) = Store : &:r7_3, r7_2 # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 8| v8_1(void) = NoOp : -# 1| v1_10(void) = ReturnVoid : -# 1| v1_11(void) = UnmodeledUse : mu* -# 1| v1_12(void) = AliasedUse : m1_3 -# 1| v1_13(void) = ExitFunction : +# 1| v1_9(void) = ReturnVoid : +# 1| v1_10(void) = AliasedUse : m1_3 +# 1| v1_11(void) = ExitFunction : # 12| void test01(int, int) # 12| Block 0 @@ -81,16 +78,14 @@ test.cpp: # 12| valnum = unique # 12| m12_4(unknown) = Chi : total:m12_2, partial:m12_3 # 12| valnum = unique -# 12| mu12_5(unknown) = UnmodeledDefinition : -# 12| valnum = unique -# 12| r12_6(glval) = VariableAddress[p0] : -# 12| valnum = r12_6, r16_1, r17_1 -# 12| m12_7(int) = InitializeParameter[p0] : &:r12_6 -# 12| valnum = m12_7, r16_2, r17_2 -# 12| r12_8(glval) = VariableAddress[p1] : -# 12| valnum = r12_8, r16_3, r17_3 -# 12| m12_9(int) = InitializeParameter[p1] : &:r12_8 -# 12| valnum = m12_9, r16_4, r17_4 +# 12| r12_5(glval) = VariableAddress[p0] : +# 12| valnum = r12_5, r16_1, r17_1 +# 12| m12_6(int) = InitializeParameter[p0] : &:r12_5 +# 12| valnum = m12_6, r16_2, r17_2 +# 12| r12_7(glval) = VariableAddress[p1] : +# 12| valnum = r12_7, r16_3, r17_3 +# 12| m12_8(int) = InitializeParameter[p1] : &:r12_7 +# 12| valnum = m12_8, r16_4, r17_4 # 13| r13_1(glval) = VariableAddress[x] : # 13| valnum = r13_1, r16_9, r17_9, r18_1 # 13| m13_2(int) = Uninitialized[x] : &:r13_1 @@ -104,13 +99,13 @@ test.cpp: # 14| m14_2(unsigned char) = Uninitialized[b] : &:r14_1 # 14| valnum = unique # 16| r16_1(glval) = VariableAddress[p0] : -# 16| valnum = r12_6, r16_1, r17_1 -# 16| r16_2(int) = Load : &:r16_1, m12_7 -# 16| valnum = m12_7, r16_2, r17_2 +# 16| valnum = r12_5, r16_1, r17_1 +# 16| r16_2(int) = Load : &:r16_1, m12_6 +# 16| valnum = m12_6, r16_2, r17_2 # 16| r16_3(glval) = VariableAddress[p1] : -# 16| valnum = r12_8, r16_3, r17_3 -# 16| r16_4(int) = Load : &:r16_3, m12_9 -# 16| valnum = m12_9, r16_4, r17_4 +# 16| valnum = r12_7, r16_3, r17_3 +# 16| r16_4(int) = Load : &:r16_3, m12_8 +# 16| valnum = m12_8, r16_4, r17_4 # 16| r16_5(int) = Add : r16_2, r16_4 # 16| valnum = r16_5, r17_5 # 16| r16_6(glval) = VariableAddress[global01] : @@ -124,13 +119,13 @@ test.cpp: # 16| m16_10(int) = Store : &:r16_9, r16_8 # 16| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 17| r17_1(glval) = VariableAddress[p0] : -# 17| valnum = r12_6, r16_1, r17_1 -# 17| r17_2(int) = Load : &:r17_1, m12_7 -# 17| valnum = m12_7, r16_2, r17_2 +# 17| valnum = r12_5, r16_1, r17_1 +# 17| r17_2(int) = Load : &:r17_1, m12_6 +# 17| valnum = m12_6, r16_2, r17_2 # 17| r17_3(glval) = VariableAddress[p1] : -# 17| valnum = r12_8, r16_3, r17_3 -# 17| r17_4(int) = Load : &:r17_3, m12_9 -# 17| valnum = m12_9, r16_4, r17_4 +# 17| valnum = r12_7, r16_3, r17_3 +# 17| r17_4(int) = Load : &:r17_3, m12_8 +# 17| valnum = m12_8, r16_4, r17_4 # 17| r17_5(int) = Add : r17_2, r17_4 # 17| valnum = r16_5, r17_5 # 17| r17_6(glval) = VariableAddress[global01] : @@ -152,10 +147,9 @@ test.cpp: # 18| m18_4(int) = Store : &:r18_3, r18_2 # 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 19| v19_1(void) = NoOp : -# 12| v12_10(void) = ReturnVoid : -# 12| v12_11(void) = UnmodeledUse : mu* -# 12| v12_12(void) = AliasedUse : m12_3 -# 12| v12_13(void) = ExitFunction : +# 12| v12_9(void) = ReturnVoid : +# 12| v12_10(void) = AliasedUse : m12_3 +# 12| v12_11(void) = ExitFunction : # 25| void test02(int, int) # 25| Block 0 @@ -166,16 +160,14 @@ test.cpp: # 25| valnum = unique # 25| m25_4(unknown) = Chi : total:m25_2, partial:m25_3 # 25| valnum = unique -# 25| mu25_5(unknown) = UnmodeledDefinition : -# 25| valnum = unique -# 25| r25_6(glval) = VariableAddress[p0] : -# 25| valnum = r25_6, r29_1, r31_1 -# 25| m25_7(int) = InitializeParameter[p0] : &:r25_6 -# 25| valnum = m25_7, r29_2, r31_2 -# 25| r25_8(glval) = VariableAddress[p1] : -# 25| valnum = r25_8, r29_3, r31_3 -# 25| m25_9(int) = InitializeParameter[p1] : &:r25_8 -# 25| valnum = m25_9, r29_4, r31_4 +# 25| r25_5(glval) = VariableAddress[p0] : +# 25| valnum = r25_5, r29_1, r31_1 +# 25| m25_6(int) = InitializeParameter[p0] : &:r25_5 +# 25| valnum = m25_6, r29_2, r31_2 +# 25| r25_7(glval) = VariableAddress[p1] : +# 25| valnum = r25_7, r29_3, r31_3 +# 25| m25_8(int) = InitializeParameter[p1] : &:r25_7 +# 25| valnum = m25_8, r29_4, r31_4 # 26| r26_1(glval) = VariableAddress[x] : # 26| valnum = r26_1, r29_9, r31_9, r32_1 # 26| m26_2(int) = Uninitialized[x] : &:r26_1 @@ -189,13 +181,13 @@ test.cpp: # 27| m27_2(unsigned char) = Uninitialized[b] : &:r27_1 # 27| valnum = unique # 29| r29_1(glval) = VariableAddress[p0] : -# 29| valnum = r25_6, r29_1, r31_1 -# 29| r29_2(int) = Load : &:r29_1, m25_7 -# 29| valnum = m25_7, r29_2, r31_2 +# 29| valnum = r25_5, r29_1, r31_1 +# 29| r29_2(int) = Load : &:r29_1, m25_6 +# 29| valnum = m25_6, r29_2, r31_2 # 29| r29_3(glval) = VariableAddress[p1] : -# 29| valnum = r25_8, r29_3, r31_3 -# 29| r29_4(int) = Load : &:r29_3, m25_9 -# 29| valnum = m25_9, r29_4, r31_4 +# 29| valnum = r25_7, r29_3, r31_3 +# 29| r29_4(int) = Load : &:r29_3, m25_8 +# 29| valnum = m25_8, r29_4, r31_4 # 29| r29_5(int) = Add : r29_2, r29_4 # 29| valnum = r29_5, r31_5 # 29| r29_6(glval) = VariableAddress[global02] : @@ -216,13 +208,13 @@ test.cpp: # 30| m30_4(unknown) = Chi : total:m25_4, partial:m30_3 # 30| valnum = unique # 31| r31_1(glval) = VariableAddress[p0] : -# 31| valnum = r25_6, r29_1, r31_1 -# 31| r31_2(int) = Load : &:r31_1, m25_7 -# 31| valnum = m25_7, r29_2, r31_2 +# 31| valnum = r25_5, r29_1, r31_1 +# 31| r31_2(int) = Load : &:r31_1, m25_6 +# 31| valnum = m25_6, r29_2, r31_2 # 31| r31_3(glval) = VariableAddress[p1] : -# 31| valnum = r25_8, r29_3, r31_3 -# 31| r31_4(int) = Load : &:r31_3, m25_9 -# 31| valnum = m25_9, r29_4, r31_4 +# 31| valnum = r25_7, r29_3, r31_3 +# 31| r31_4(int) = Load : &:r31_3, m25_8 +# 31| valnum = m25_8, r29_4, r31_4 # 31| r31_5(int) = Add : r31_2, r31_4 # 31| valnum = r29_5, r31_5 # 31| r31_6(glval) = VariableAddress[global02] : @@ -244,10 +236,9 @@ test.cpp: # 32| m32_4(int) = Store : &:r32_3, r32_2 # 32| valnum = m31_10, m32_4, r31_8, r32_2 # 33| v33_1(void) = NoOp : -# 25| v25_10(void) = ReturnVoid : -# 25| v25_11(void) = UnmodeledUse : mu* -# 25| v25_12(void) = AliasedUse : ~m30_4 -# 25| v25_13(void) = ExitFunction : +# 25| v25_9(void) = ReturnVoid : +# 25| v25_10(void) = AliasedUse : ~m30_4 +# 25| v25_11(void) = ExitFunction : # 39| void test03(int, int, int*) # 39| Block 0 @@ -258,23 +249,21 @@ test.cpp: # 39| valnum = unique # 39| m39_4(unknown) = Chi : total:m39_2, partial:m39_3 # 39| valnum = unique -# 39| mu39_5(unknown) = UnmodeledDefinition : -# 39| valnum = unique -# 39| r39_6(glval) = VariableAddress[p0] : -# 39| valnum = r39_6, r43_1, r45_1 -# 39| m39_7(int) = InitializeParameter[p0] : &:r39_6 -# 39| valnum = m39_7, r43_2, r45_2 -# 39| r39_8(glval) = VariableAddress[p1] : -# 39| valnum = r39_8, r43_3, r45_3 -# 39| m39_9(int) = InitializeParameter[p1] : &:r39_8 -# 39| valnum = m39_9, r43_4, r45_4 -# 39| r39_10(glval) = VariableAddress[p2] : -# 39| valnum = r39_10, r44_2 -# 39| m39_11(int *) = InitializeParameter[p2] : &:r39_10 -# 39| valnum = m39_11, r39_12, r44_3, r44_4 -# 39| r39_12(int *) = Load : &:r39_10, m39_11 -# 39| valnum = m39_11, r39_12, r44_3, r44_4 -# 39| m39_13(unknown) = InitializeIndirection[p2] : &:r39_12 +# 39| r39_5(glval) = VariableAddress[p0] : +# 39| valnum = r39_5, r43_1, r45_1 +# 39| m39_6(int) = InitializeParameter[p0] : &:r39_5 +# 39| valnum = m39_6, r43_2, r45_2 +# 39| r39_7(glval) = VariableAddress[p1] : +# 39| valnum = r39_7, r43_3, r45_3 +# 39| m39_8(int) = InitializeParameter[p1] : &:r39_7 +# 39| valnum = m39_8, r43_4, r45_4 +# 39| r39_9(glval) = VariableAddress[p2] : +# 39| valnum = r39_9, r44_2 +# 39| m39_10(int *) = InitializeParameter[p2] : &:r39_9 +# 39| valnum = m39_10, r39_11, r44_3, r44_4 +# 39| r39_11(int *) = Load : &:r39_9, m39_10 +# 39| valnum = m39_10, r39_11, r44_3, r44_4 +# 39| m39_12(unknown) = InitializeIndirection[p2] : &:r39_11 # 39| valnum = unique # 40| r40_1(glval) = VariableAddress[x] : # 40| valnum = r40_1, r43_9, r45_9, r46_1 @@ -289,13 +278,13 @@ test.cpp: # 41| m41_2(unsigned char) = Uninitialized[b] : &:r41_1 # 41| valnum = unique # 43| r43_1(glval) = VariableAddress[p0] : -# 43| valnum = r39_6, r43_1, r45_1 -# 43| r43_2(int) = Load : &:r43_1, m39_7 -# 43| valnum = m39_7, r43_2, r45_2 +# 43| valnum = r39_5, r43_1, r45_1 +# 43| r43_2(int) = Load : &:r43_1, m39_6 +# 43| valnum = m39_6, r43_2, r45_2 # 43| r43_3(glval) = VariableAddress[p1] : -# 43| valnum = r39_8, r43_3, r45_3 -# 43| r43_4(int) = Load : &:r43_3, m39_9 -# 43| valnum = m39_9, r43_4, r45_4 +# 43| valnum = r39_7, r43_3, r45_3 +# 43| r43_4(int) = Load : &:r43_3, m39_8 +# 43| valnum = m39_8, r43_4, r45_4 # 43| r43_5(int) = Add : r43_2, r43_4 # 43| valnum = r43_5, r45_5 # 43| r43_6(glval) = VariableAddress[global03] : @@ -311,23 +300,23 @@ test.cpp: # 44| r44_1(int) = Constant[0] : # 44| valnum = m44_5, r44_1 # 44| r44_2(glval) = VariableAddress[p2] : -# 44| valnum = r39_10, r44_2 -# 44| r44_3(int *) = Load : &:r44_2, m39_11 -# 44| valnum = m39_11, r39_12, r44_3, r44_4 +# 44| valnum = r39_9, r44_2 +# 44| r44_3(int *) = Load : &:r44_2, m39_10 +# 44| valnum = m39_10, r39_11, r44_3, r44_4 # 44| r44_4(glval) = CopyValue : r44_3 -# 44| valnum = m39_11, r39_12, r44_3, r44_4 +# 44| valnum = m39_10, r39_11, r44_3, r44_4 # 44| m44_5(int) = Store : &:r44_4, r44_1 # 44| valnum = m44_5, r44_1 -# 44| m44_6(unknown) = Chi : total:m39_13, partial:m44_5 +# 44| m44_6(unknown) = Chi : total:m39_12, partial:m44_5 # 44| valnum = unique # 45| r45_1(glval) = VariableAddress[p0] : -# 45| valnum = r39_6, r43_1, r45_1 -# 45| r45_2(int) = Load : &:r45_1, m39_7 -# 45| valnum = m39_7, r43_2, r45_2 +# 45| valnum = r39_5, r43_1, r45_1 +# 45| r45_2(int) = Load : &:r45_1, m39_6 +# 45| valnum = m39_6, r43_2, r45_2 # 45| r45_3(glval) = VariableAddress[p1] : -# 45| valnum = r39_8, r43_3, r45_3 -# 45| r45_4(int) = Load : &:r45_3, m39_9 -# 45| valnum = m39_9, r43_4, r45_4 +# 45| valnum = r39_7, r43_3, r45_3 +# 45| r45_4(int) = Load : &:r45_3, m39_8 +# 45| valnum = m39_8, r43_4, r45_4 # 45| r45_5(int) = Add : r45_2, r45_4 # 45| valnum = r43_5, r45_5 # 45| r45_6(glval) = VariableAddress[global03] : @@ -349,11 +338,10 @@ test.cpp: # 46| m46_4(int) = Store : &:r46_3, r46_2 # 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2 # 47| v47_1(void) = NoOp : -# 39| v39_14(void) = ReturnIndirection[p2] : &:r39_12, m44_6 -# 39| v39_15(void) = ReturnVoid : -# 39| v39_16(void) = UnmodeledUse : mu* -# 39| v39_17(void) = AliasedUse : m39_3 -# 39| v39_18(void) = ExitFunction : +# 39| v39_13(void) = ReturnIndirection[p2] : &:r39_11, m44_6 +# 39| v39_14(void) = ReturnVoid : +# 39| v39_15(void) = AliasedUse : m39_3 +# 39| v39_16(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 @@ -364,23 +352,21 @@ test.cpp: # 49| valnum = unique # 49| m49_4(unknown) = Chi : total:m49_2, partial:m49_3 # 49| valnum = unique -# 49| mu49_5(unknown) = UnmodeledDefinition : +# 49| r49_5(glval) = VariableAddress[str] : +# 49| valnum = r49_5, r53_2, r56_6 +# 49| m49_6(char *) = InitializeParameter[str] : &:r49_5 +# 49| valnum = m49_6, r49_7, r53_3, r56_7 +# 49| r49_7(char *) = Load : &:r49_5, m49_6 +# 49| valnum = m49_6, r49_7, r53_3, r56_7 +# 49| m49_8(unknown) = InitializeIndirection[str] : &:r49_7 # 49| valnum = unique -# 49| r49_6(glval) = VariableAddress[str] : -# 49| valnum = r49_6, r53_2, r56_6 -# 49| m49_7(char *) = InitializeParameter[str] : &:r49_6 -# 49| valnum = m49_7, r49_8, r53_3, r56_7 -# 49| r49_8(char *) = Load : &:r49_6, m49_7 -# 49| valnum = m49_7, r49_8, r53_3, r56_7 -# 49| m49_9(unknown) = InitializeIndirection[str] : &:r49_8 -# 49| valnum = unique -# 49| r49_10(glval) = VariableAddress[chars] : -# 49| valnum = r49_10, r55_1 -# 49| m49_11(char *) = InitializeParameter[chars] : &:r49_10 -# 49| valnum = m49_11, m55_4, r49_12, r55_2 -# 49| r49_12(char *) = Load : &:r49_10, m49_11 -# 49| valnum = m49_11, m55_4, r49_12, r55_2 -# 49| m49_13(unknown) = InitializeIndirection[chars] : &:r49_12 +# 49| r49_9(glval) = VariableAddress[chars] : +# 49| valnum = r49_9, r55_1 +# 49| m49_10(char *) = InitializeParameter[chars] : &:r49_9 +# 49| valnum = m49_10, m55_4, r49_11, r55_2 +# 49| r49_11(char *) = Load : &:r49_9, m49_10 +# 49| valnum = m49_10, m55_4, r49_11, r55_2 +# 49| m49_12(unknown) = InitializeIndirection[chars] : &:r49_11 # 49| valnum = unique # 50| r50_1(glval) = VariableAddress[ptr] : # 50| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 @@ -398,10 +384,10 @@ test.cpp: # 53| m53_1(unsigned int) = Phi : from 0:m51_3, from 8:m62_5 # 53| valnum = m53_1, m65_4, r62_2, r65_3 # 53| r53_2(glval) = VariableAddress[str] : -# 53| valnum = r49_6, r53_2, r56_6 -# 53| r53_3(char *) = Load : &:r53_2, m49_7 -# 53| valnum = m49_7, r49_8, r53_3, r56_7 -# 53| r53_4(char) = Load : &:r53_3, ~m49_9 +# 53| valnum = r49_5, r53_2, r56_6 +# 53| r53_3(char *) = Load : &:r53_2, m49_6 +# 53| valnum = m49_6, r49_7, r53_3, r56_7 +# 53| r53_4(char) = Load : &:r53_3, ~m49_8 # 53| valnum = r53_4, r56_8 # 53| r53_5(int) = Convert : r53_4 # 53| valnum = r53_5, r56_9 @@ -415,13 +401,13 @@ test.cpp: # 55| Block 2 # 55| r55_1(glval) = VariableAddress[chars] : -# 55| valnum = r49_10, r55_1 -# 55| r55_2(char *) = Load : &:r55_1, m49_11 -# 55| valnum = m49_11, m55_4, r49_12, r55_2 +# 55| valnum = r49_9, r55_1 +# 55| r55_2(char *) = Load : &:r55_1, m49_10 +# 55| valnum = m49_10, m55_4, r49_11, r55_2 # 55| r55_3(glval) = VariableAddress[ptr] : # 55| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 # 55| m55_4(char *) = Store : &:r55_3, r55_2 -# 55| valnum = m49_11, m55_4, r49_12, r55_2 +# 55| valnum = m49_10, m55_4, r49_11, r55_2 #-----| Goto -> Block 3 # 56| Block 3 @@ -436,10 +422,10 @@ test.cpp: # 56| r56_5(int) = Convert : r56_4 # 56| valnum = r56_15, r56_5, r59_4 # 56| r56_6(glval) = VariableAddress[str] : -# 56| valnum = r49_6, r53_2, r56_6 -# 56| r56_7(char *) = Load : &:r56_6, m49_7 -# 56| valnum = m49_7, r49_8, r53_3, r56_7 -# 56| r56_8(char) = Load : &:r56_7, ~m49_9 +# 56| valnum = r49_5, r53_2, r56_6 +# 56| r56_7(char *) = Load : &:r56_6, m49_6 +# 56| valnum = m49_6, r49_7, r53_3, r56_7 +# 56| r56_8(char) = Load : &:r56_7, ~m49_8 # 56| valnum = r53_4, r56_8 # 56| r56_9(int) = Convert : r56_8 # 56| valnum = r53_5, r56_9 @@ -516,21 +502,20 @@ test.cpp: # 63| Block 9 # 63| v63_1(void) = NoOp : # 65| r65_1(glval) = VariableAddress[#return] : -# 65| valnum = r49_16, r65_1 +# 65| valnum = r49_15, r65_1 # 65| r65_2(glval) = VariableAddress[result] : # 65| valnum = r51_1, r62_1, r65_2 # 65| r65_3(unsigned int) = Load : &:r65_2, m53_1 # 65| valnum = m53_1, m65_4, r62_2, r65_3 # 65| m65_4(unsigned int) = Store : &:r65_1, r65_3 # 65| valnum = m53_1, m65_4, r62_2, r65_3 -# 49| v49_14(void) = ReturnIndirection[str] : &:r49_8, m49_9 -# 49| v49_15(void) = ReturnIndirection[chars] : &:r49_12, m49_13 -# 49| r49_16(glval) = VariableAddress[#return] : -# 49| valnum = r49_16, r65_1 -# 49| v49_17(void) = ReturnValue : &:r49_16, m65_4 -# 49| v49_18(void) = UnmodeledUse : mu* -# 49| v49_19(void) = AliasedUse : m49_3 -# 49| v49_20(void) = ExitFunction : +# 49| v49_13(void) = ReturnIndirection[str] : &:r49_7, m49_8 +# 49| v49_14(void) = ReturnIndirection[chars] : &:r49_11, m49_12 +# 49| r49_15(glval) = VariableAddress[#return] : +# 49| valnum = r49_15, r65_1 +# 49| v49_16(void) = ReturnValue : &:r49_15, m65_4 +# 49| v49_17(void) = AliasedUse : m49_3 +# 49| v49_18(void) = ExitFunction : # 75| void test04(two_values*) # 75| Block 0 @@ -541,15 +526,13 @@ test.cpp: # 75| valnum = unique # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 # 75| valnum = unique -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| valnum = unique -# 75| r75_6(glval) = VariableAddress[vals] : -# 75| valnum = r75_6, r79_4, r79_9 -# 75| m75_7(two_values *) = InitializeParameter[vals] : &:r75_6 -# 75| valnum = m75_7, r75_8, r79_10, r79_5 -# 75| r75_8(two_values *) = Load : &:r75_6, m75_7 -# 75| valnum = m75_7, r75_8, r79_10, r79_5 -# 75| m75_9(unknown) = InitializeIndirection[vals] : &:r75_8 +# 75| r75_5(glval) = VariableAddress[vals] : +# 75| valnum = r75_5, r79_4, r79_9 +# 75| m75_6(two_values *) = InitializeParameter[vals] : &:r75_5 +# 75| valnum = m75_6, r75_7, r79_10, r79_5 +# 75| r75_7(two_values *) = Load : &:r75_5, m75_6 +# 75| valnum = m75_6, r75_7, r79_10, r79_5 +# 75| m75_8(unknown) = InitializeIndirection[vals] : &:r75_7 # 75| valnum = unique # 77| r77_1(glval) = VariableAddress[v] : # 77| valnum = r77_1, r79_1, r80_6 @@ -572,22 +555,22 @@ test.cpp: # 79| r79_3(int) = Convert : r79_2 # 79| valnum = unique # 79| r79_4(glval) = VariableAddress[vals] : -# 79| valnum = r75_6, r79_4, r79_9 -# 79| r79_5(two_values *) = Load : &:r79_4, m75_7 -# 79| valnum = m75_7, r75_8, r79_10, r79_5 +# 79| valnum = r75_5, r79_4, r79_9 +# 79| r79_5(two_values *) = Load : &:r79_4, m75_6 +# 79| valnum = m75_6, r75_7, r79_10, r79_5 # 79| r79_6(glval) = FieldAddress[val1] : r79_5 # 79| valnum = unique -# 79| r79_7(signed short) = Load : &:r79_6, ~m75_9 +# 79| r79_7(signed short) = Load : &:r79_6, ~m75_8 # 79| valnum = unique # 79| r79_8(int) = Convert : r79_7 # 79| valnum = unique # 79| r79_9(glval) = VariableAddress[vals] : -# 79| valnum = r75_6, r79_4, r79_9 -# 79| r79_10(two_values *) = Load : &:r79_9, m75_7 -# 79| valnum = m75_7, r75_8, r79_10, r79_5 +# 79| valnum = r75_5, r79_4, r79_9 +# 79| r79_10(two_values *) = Load : &:r79_9, m75_6 +# 79| valnum = m75_6, r75_7, r79_10, r79_5 # 79| r79_11(glval) = FieldAddress[val2] : r79_10 # 79| valnum = unique -# 79| r79_12(signed short) = Load : &:r79_11, ~m75_9 +# 79| r79_12(signed short) = Load : &:r79_11, ~m75_8 # 79| valnum = unique # 79| r79_13(int) = Convert : r79_12 # 79| valnum = unique @@ -620,52 +603,49 @@ test.cpp: # 82| m82_1(unknown) = Phi : from 0:~m77_5, from 1:~m80_4 # 82| valnum = unique # 82| v82_2(void) = NoOp : -# 75| v75_10(void) = ReturnIndirection[vals] : &:r75_8, m75_9 -# 75| v75_11(void) = ReturnVoid : -# 75| v75_12(void) = UnmodeledUse : mu* -# 75| v75_13(void) = AliasedUse : ~m82_1 -# 75| v75_14(void) = ExitFunction : +# 75| v75_9(void) = ReturnIndirection[vals] : &:r75_7, m75_8 +# 75| v75_10(void) = ReturnVoid : +# 75| v75_11(void) = AliasedUse : ~m82_1 +# 75| v75_12(void) = ExitFunction : # 84| void test05(int, int, void*) # 84| Block 0 -# 84| v84_1(void) = EnterFunction : -# 84| m84_2(unknown) = AliasedDefinition : +# 84| v84_1(void) = EnterFunction : +# 84| m84_2(unknown) = AliasedDefinition : # 84| valnum = unique -# 84| m84_3(unknown) = InitializeNonLocal : +# 84| m84_3(unknown) = InitializeNonLocal : # 84| valnum = unique -# 84| m84_4(unknown) = Chi : total:m84_2, partial:m84_3 +# 84| m84_4(unknown) = Chi : total:m84_2, partial:m84_3 # 84| valnum = unique -# 84| mu84_5(unknown) = UnmodeledDefinition : +# 84| r84_5(glval) = VariableAddress[x] : +# 84| valnum = r84_5, r88_11 +# 84| m84_6(int) = InitializeParameter[x] : &:r84_5 +# 84| valnum = m84_6, m88_14, r88_12 +# 84| r84_7(glval) = VariableAddress[y] : +# 84| valnum = r84_7, r88_15 +# 84| m84_8(int) = InitializeParameter[y] : &:r84_7 +# 84| valnum = m84_8, m88_18, r88_16 +# 84| r84_9(glval) = VariableAddress[p] : +# 84| valnum = r84_9, r88_1 +# 84| m84_10(void *) = InitializeParameter[p] : &:r84_9 +# 84| valnum = m84_10, r84_11, r88_2 +# 84| r84_11(void *) = Load : &:r84_9, m84_10 +# 84| valnum = m84_10, r84_11, r88_2 +# 84| m84_12(unknown) = InitializeIndirection[p] : &:r84_11 # 84| valnum = unique -# 84| r84_6(glval) = VariableAddress[x] : -# 84| valnum = r84_6, r88_11 -# 84| m84_7(int) = InitializeParameter[x] : &:r84_6 -# 84| valnum = m84_7, m88_14, r88_12 -# 84| r84_8(glval) = VariableAddress[y] : -# 84| valnum = r84_8, r88_15 -# 84| m84_9(int) = InitializeParameter[y] : &:r84_8 -# 84| valnum = m84_9, m88_18, r88_16 -# 84| r84_10(glval) = VariableAddress[p] : -# 84| valnum = r84_10, r88_1 -# 84| m84_11(void *) = InitializeParameter[p] : &:r84_10 -# 84| valnum = m84_11, r84_12, r88_2 -# 84| r84_12(void *) = Load : &:r84_10, m84_11 -# 84| valnum = m84_11, r84_12, r88_2 -# 84| m84_13(unknown) = InitializeIndirection[p] : &:r84_12 -# 84| valnum = unique -# 86| r86_1(glval) = VariableAddress[v] : +# 86| r86_1(glval) = VariableAddress[v] : # 86| valnum = r86_1, r88_9 -# 86| m86_2(int) = Uninitialized[v] : &:r86_1 +# 86| m86_2(int) = Uninitialized[v] : &:r86_1 # 86| valnum = unique -# 88| r88_1(glval) = VariableAddress[p] : -# 88| valnum = r84_10, r88_1 -# 88| r88_2(void *) = Load : &:r88_1, m84_11 -# 88| valnum = m84_11, r84_12, r88_2 -# 88| r88_3(void *) = Constant[0] : +# 88| r88_1(glval) = VariableAddress[p] : +# 88| valnum = r84_9, r88_1 +# 88| r88_2(void *) = Load : &:r88_1, m84_10 +# 88| valnum = m84_10, r84_11, r88_2 +# 88| r88_3(void *) = Constant[0] : # 88| valnum = unique -# 88| r88_4(bool) = CompareNE : r88_2, r88_3 +# 88| r88_4(bool) = CompareNE : r88_2, r88_3 # 88| valnum = unique -# 88| v88_5(void) = ConditionalBranch : r88_4 +# 88| v88_5(void) = ConditionalBranch : r88_4 #-----| False -> Block 3 #-----| True -> Block 2 @@ -681,32 +661,31 @@ test.cpp: # 88| m88_10(int) = Store : &:r88_9, r88_8 # 88| valnum = m88_10, m88_6, r88_8 # 89| v89_1(void) = NoOp : -# 84| v84_14(void) = ReturnIndirection[p] : &:r84_12, m84_13 -# 84| v84_15(void) = ReturnVoid : -# 84| v84_16(void) = UnmodeledUse : mu* -# 84| v84_17(void) = AliasedUse : m84_3 -# 84| v84_18(void) = ExitFunction : +# 84| v84_13(void) = ReturnIndirection[p] : &:r84_11, m84_12 +# 84| v84_14(void) = ReturnVoid : +# 84| v84_15(void) = AliasedUse : m84_3 +# 84| v84_16(void) = ExitFunction : # 88| Block 2 # 88| r88_11(glval) = VariableAddress[x] : -# 88| valnum = r84_6, r88_11 -# 88| r88_12(int) = Load : &:r88_11, m84_7 -# 88| valnum = m84_7, m88_14, r88_12 +# 88| valnum = r84_5, r88_11 +# 88| r88_12(int) = Load : &:r88_11, m84_6 +# 88| valnum = m84_6, m88_14, r88_12 # 88| r88_13(glval) = VariableAddress[#temp88:7] : # 88| valnum = r88_13, r88_17, r88_7 # 88| m88_14(int) = Store : &:r88_13, r88_12 -# 88| valnum = m84_7, m88_14, r88_12 +# 88| valnum = m84_6, m88_14, r88_12 #-----| Goto -> Block 1 # 88| Block 3 # 88| r88_15(glval) = VariableAddress[y] : -# 88| valnum = r84_8, r88_15 -# 88| r88_16(int) = Load : &:r88_15, m84_9 -# 88| valnum = m84_9, m88_18, r88_16 +# 88| valnum = r84_7, r88_15 +# 88| r88_16(int) = Load : &:r88_15, m84_8 +# 88| valnum = m84_8, m88_18, r88_16 # 88| r88_17(glval) = VariableAddress[#temp88:7] : # 88| valnum = r88_13, r88_17, r88_7 # 88| m88_18(int) = Store : &:r88_17, r88_16 -# 88| valnum = m84_9, m88_18, r88_16 +# 88| valnum = m84_8, m88_18, r88_16 #-----| Goto -> Block 1 # 91| int regression_test00() @@ -718,8 +697,6 @@ test.cpp: # 91| valnum = unique # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 # 91| valnum = unique -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| valnum = unique # 92| r92_1(glval) = VariableAddress[x] : # 92| valnum = r92_1, r92_3, r93_2 # 92| r92_2(int) = Constant[10] : @@ -733,19 +710,18 @@ test.cpp: # 92| m92_6(int) = Store : &:r92_1, r92_5 # 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 # 93| r93_1(glval) = VariableAddress[#return] : -# 93| valnum = r91_6, r93_1 +# 93| valnum = r91_5, r93_1 # 93| r93_2(glval) = VariableAddress[x] : # 93| valnum = r92_1, r92_3, r93_2 # 93| r93_3(int) = Load : &:r93_2, m92_6 # 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 # 93| m93_4(int) = Store : &:r93_1, r93_3 # 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 -# 91| r91_6(glval) = VariableAddress[#return] : -# 91| valnum = r91_6, r93_1 -# 91| v91_7(void) = ReturnValue : &:r91_6, m93_4 -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : m91_3 -# 91| v91_10(void) = ExitFunction : +# 91| r91_5(glval) = VariableAddress[#return] : +# 91| valnum = r91_5, r93_1 +# 91| v91_6(void) = ReturnValue : &:r91_5, m93_4 +# 91| v91_7(void) = AliasedUse : m91_3 +# 91| v91_8(void) = ExitFunction : # 104| int inheritanceConversions(Derived*) # 104| Block 0 @@ -756,36 +732,34 @@ test.cpp: # 104| valnum = unique # 104| m104_4(unknown) = Chi : total:m104_2, partial:m104_3 # 104| valnum = unique -# 104| mu104_5(unknown) = UnmodeledDefinition : -# 104| valnum = unique -# 104| r104_6(glval) = VariableAddress[pd] : -# 104| valnum = r104_6, r105_2, r106_2 -# 104| m104_7(Derived *) = InitializeParameter[pd] : &:r104_6 -# 104| valnum = m104_7, r104_8, r105_3, r106_3 -# 104| r104_8(Derived *) = Load : &:r104_6, m104_7 -# 104| valnum = m104_7, r104_8, r105_3, r106_3 -# 104| m104_9(unknown) = InitializeIndirection[pd] : &:r104_8 +# 104| r104_5(glval) = VariableAddress[pd] : +# 104| valnum = r104_5, r105_2, r106_2 +# 104| m104_6(Derived *) = InitializeParameter[pd] : &:r104_5 +# 104| valnum = m104_6, r104_7, r105_3, r106_3 +# 104| r104_7(Derived *) = Load : &:r104_5, m104_6 +# 104| valnum = m104_6, r104_7, r105_3, r106_3 +# 104| m104_8(unknown) = InitializeIndirection[pd] : &:r104_7 # 104| valnum = unique # 105| r105_1(glval) = VariableAddress[x] : # 105| valnum = unique # 105| r105_2(glval) = VariableAddress[pd] : -# 105| valnum = r104_6, r105_2, r106_2 -# 105| r105_3(Derived *) = Load : &:r105_2, m104_7 -# 105| valnum = m104_7, r104_8, r105_3, r106_3 +# 105| valnum = r104_5, r105_2, r106_2 +# 105| r105_3(Derived *) = Load : &:r105_2, m104_6 +# 105| valnum = m104_6, r104_7, r105_3, r106_3 # 105| r105_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r105_3 # 105| valnum = m106_5, r105_4, r106_4, r107_3 # 105| r105_5(glval) = FieldAddress[b] : r105_4 # 105| valnum = r105_5, r107_4 -# 105| r105_6(int) = Load : &:r105_5, ~m104_9 +# 105| r105_6(int) = Load : &:r105_5, ~m104_8 # 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 105| m105_7(int) = Store : &:r105_1, r105_6 # 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 106| r106_1(glval) = VariableAddress[pb] : # 106| valnum = r106_1, r107_2 # 106| r106_2(glval) = VariableAddress[pd] : -# 106| valnum = r104_6, r105_2, r106_2 -# 106| r106_3(Derived *) = Load : &:r106_2, m104_7 -# 106| valnum = m104_7, r104_8, r105_3, r106_3 +# 106| valnum = r104_5, r105_2, r106_2 +# 106| r106_3(Derived *) = Load : &:r106_2, m104_6 +# 106| valnum = m104_6, r104_7, r105_3, r106_3 # 106| r106_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r106_3 # 106| valnum = m106_5, r105_4, r106_4, r107_3 # 106| m106_5(Base *) = Store : &:r106_1, r106_4 @@ -798,25 +772,24 @@ test.cpp: # 107| valnum = m106_5, r105_4, r106_4, r107_3 # 107| r107_4(glval) = FieldAddress[b] : r107_3 # 107| valnum = r105_5, r107_4 -# 107| r107_5(int) = Load : &:r107_4, ~m104_9 +# 107| r107_5(int) = Load : &:r107_4, ~m104_8 # 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 107| m107_6(int) = Store : &:r107_1, r107_5 # 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 109| r109_1(glval) = VariableAddress[#return] : -# 109| valnum = r104_11, r109_1 +# 109| valnum = r104_10, r109_1 # 109| r109_2(glval) = VariableAddress[y] : # 109| valnum = r107_1, r109_2 # 109| r109_3(int) = Load : &:r109_2, m107_6 # 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 109| m109_4(int) = Store : &:r109_1, r109_3 # 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 -# 104| v104_10(void) = ReturnIndirection[pd] : &:r104_8, m104_9 -# 104| r104_11(glval) = VariableAddress[#return] : -# 104| valnum = r104_11, r109_1 -# 104| v104_12(void) = ReturnValue : &:r104_11, m109_4 -# 104| v104_13(void) = UnmodeledUse : mu* -# 104| v104_14(void) = AliasedUse : m104_3 -# 104| v104_15(void) = ExitFunction : +# 104| v104_9(void) = ReturnIndirection[pd] : &:r104_7, m104_8 +# 104| r104_10(glval) = VariableAddress[#return] : +# 104| valnum = r104_10, r109_1 +# 104| v104_11(void) = ReturnValue : &:r104_10, m109_4 +# 104| v104_12(void) = AliasedUse : m104_3 +# 104| v104_13(void) = ExitFunction : # 112| void test06() # 112| Block 0 @@ -827,8 +800,6 @@ test.cpp: # 112| valnum = unique # 112| m112_4(unknown) = Chi : total:m112_2, partial:m112_3 # 112| valnum = unique -# 112| mu112_5(unknown) = UnmodeledDefinition : -# 112| valnum = unique # 113| r113_1(glval) = StringConstant["a"] : # 113| valnum = r113_1, r115_1 # 114| r114_1(glval) = StringConstant["b"] : @@ -838,90 +809,86 @@ test.cpp: # 116| r116_1(glval) = StringConstant["c"] : # 116| valnum = unique # 117| v117_1(void) = NoOp : -# 112| v112_6(void) = ReturnVoid : -# 112| v112_7(void) = UnmodeledUse : mu* -# 112| v112_8(void) = AliasedUse : m112_3 -# 112| v112_9(void) = ExitFunction : +# 112| v112_5(void) = ReturnVoid : +# 112| v112_6(void) = AliasedUse : m112_3 +# 112| v112_7(void) = ExitFunction : # 124| void test_read_arg_same(A*, int) # 124| Block 0 -# 124| v124_1(void) = EnterFunction : -# 124| m124_2(unknown) = AliasedDefinition : +# 124| v124_1(void) = EnterFunction : +# 124| m124_2(unknown) = AliasedDefinition : # 124| valnum = unique -# 124| m124_3(unknown) = InitializeNonLocal : +# 124| m124_3(unknown) = InitializeNonLocal : # 124| valnum = unique -# 124| m124_4(unknown) = Chi : total:m124_2, partial:m124_3 +# 124| m124_4(unknown) = Chi : total:m124_2, partial:m124_3 # 124| valnum = unique -# 124| mu124_5(unknown) = UnmodeledDefinition : +# 124| r124_5(glval) = VariableAddress[pa] : +# 124| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 124| m124_6(A *) = InitializeParameter[pa] : &:r124_5 +# 124| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 124| r124_7(A *) = Load : &:r124_5, m124_6 +# 124| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 124| m124_8(unknown) = InitializeIndirection[pa] : &:r124_7 # 124| valnum = unique -# 124| r124_6(glval) = VariableAddress[pa] : -# 124| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 124| m124_7(A *) = InitializeParameter[pa] : &:r124_6 -# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 124| r124_8(A *) = Load : &:r124_6, m124_7 -# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 124| m124_9(unknown) = InitializeIndirection[pa] : &:r124_8 -# 124| valnum = unique -# 124| r124_10(glval) = VariableAddress[n] : -# 124| valnum = r124_10, r128_1 -# 124| m124_11(int) = InitializeParameter[n] : &:r124_10 -# 124| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 125| r125_1(glval) = VariableAddress[b] : +# 124| r124_9(glval) = VariableAddress[n] : +# 124| valnum = r124_9, r128_1 +# 124| m124_10(int) = InitializeParameter[n] : &:r124_9 +# 124| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 125| r125_1(glval) = VariableAddress[b] : # 125| valnum = unique -# 125| r125_2(glval) = VariableAddress[pa] : -# 125| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 125| r125_3(A *) = Load : &:r125_2, m124_7 -# 125| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 125| r125_4(glval) = FieldAddress[x] : r125_3 +# 125| r125_2(glval) = VariableAddress[pa] : +# 125| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 125| r125_3(A *) = Load : &:r125_2, m124_6 +# 125| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| valnum = r125_4, r126_4, r128_5, r129_4 -# 125| r125_5(int) = Load : &:r125_4, ~m124_9 +# 125| r125_5(int) = Load : &:r125_4, ~m124_8 # 125| valnum = m125_6, m126_6, r125_5, r126_5 -# 125| m125_6(int) = Store : &:r125_1, r125_5 +# 125| m125_6(int) = Store : &:r125_1, r125_5 # 125| valnum = m125_6, m126_6, r125_5, r126_5 -# 126| r126_1(glval) = VariableAddress[c] : +# 126| r126_1(glval) = VariableAddress[c] : # 126| valnum = unique -# 126| r126_2(glval) = VariableAddress[pa] : -# 126| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 126| r126_3(A *) = Load : &:r126_2, m124_7 -# 126| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 126| r126_4(glval) = FieldAddress[x] : r126_3 +# 126| r126_2(glval) = VariableAddress[pa] : +# 126| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 126| r126_3(A *) = Load : &:r126_2, m124_6 +# 126| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 126| r126_4(glval) = FieldAddress[x] : r126_3 # 126| valnum = r125_4, r126_4, r128_5, r129_4 -# 126| r126_5(int) = Load : &:r126_4, ~m124_9 +# 126| r126_5(int) = Load : &:r126_4, ~m124_8 # 126| valnum = m125_6, m126_6, r125_5, r126_5 -# 126| m126_6(int) = Store : &:r126_1, r126_5 +# 126| m126_6(int) = Store : &:r126_1, r126_5 # 126| valnum = m125_6, m126_6, r125_5, r126_5 -# 128| r128_1(glval) = VariableAddress[n] : -# 128| valnum = r124_10, r128_1 -# 128| r128_2(int) = Load : &:r128_1, m124_11 -# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 128| r128_3(glval) = VariableAddress[pa] : -# 128| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 128| r128_4(A *) = Load : &:r128_3, m124_7 -# 128| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 128| r128_5(glval) = FieldAddress[x] : r128_4 +# 128| r128_1(glval) = VariableAddress[n] : +# 128| valnum = r124_9, r128_1 +# 128| r128_2(int) = Load : &:r128_1, m124_10 +# 128| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 128| r128_3(glval) = VariableAddress[pa] : +# 128| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 128| r128_4(A *) = Load : &:r128_3, m124_6 +# 128| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 128| r128_5(glval) = FieldAddress[x] : r128_4 # 128| valnum = r125_4, r126_4, r128_5, r129_4 -# 128| m128_6(int) = Store : &:r128_5, r128_2 -# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 128| m128_7(unknown) = Chi : total:m124_9, partial:m128_6 +# 128| m128_6(int) = Store : &:r128_5, r128_2 +# 128| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 128| m128_7(unknown) = Chi : total:m124_8, partial:m128_6 # 128| valnum = unique -# 129| r129_1(glval) = VariableAddress[d] : +# 129| r129_1(glval) = VariableAddress[d] : # 129| valnum = unique -# 129| r129_2(glval) = VariableAddress[pa] : -# 129| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 129| r129_3(A *) = Load : &:r129_2, m124_7 -# 129| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 129| r129_4(glval) = FieldAddress[x] : r129_3 +# 129| r129_2(glval) = VariableAddress[pa] : +# 129| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 129| r129_3(A *) = Load : &:r129_2, m124_6 +# 129| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 129| r129_4(glval) = FieldAddress[x] : r129_3 # 129| valnum = r125_4, r126_4, r128_5, r129_4 -# 129| r129_5(int) = Load : &:r129_4, m128_6 -# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 129| m129_6(int) = Store : &:r129_1, r129_5 -# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 130| v130_1(void) = NoOp : -# 124| v124_12(void) = ReturnIndirection[pa] : &:r124_8, m128_7 -# 124| v124_13(void) = ReturnVoid : -# 124| v124_14(void) = UnmodeledUse : mu* -# 124| v124_15(void) = AliasedUse : m124_3 -# 124| v124_16(void) = ExitFunction : +# 129| r129_5(int) = Load : &:r129_4, m128_6 +# 129| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 129| m129_6(int) = Store : &:r129_1, r129_5 +# 129| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 130| v130_1(void) = NoOp : +# 124| v124_11(void) = ReturnIndirection[pa] : &:r124_7, m128_7 +# 124| v124_12(void) = ReturnVoid : +# 124| v124_13(void) = AliasedUse : m124_3 +# 124| v124_14(void) = ExitFunction : # 135| void test_read_global_same() # 135| Block 0 @@ -932,8 +899,6 @@ test.cpp: # 135| valnum = unique # 135| m135_4(unknown) = Chi : total:m135_2, partial:m135_3 # 135| valnum = unique -# 135| mu135_5(unknown) = UnmodeledDefinition : -# 135| valnum = unique # 136| r136_1(glval) = VariableAddress[b] : # 136| valnum = unique # 136| r136_2(glval) = VariableAddress[global_a] : @@ -985,10 +950,9 @@ test.cpp: # 140| m140_6(int) = Store : &:r140_1, r140_5 # 140| valnum = m140_6, r140_5 # 141| v141_1(void) = NoOp : -# 135| v135_6(void) = ReturnVoid : -# 135| v135_7(void) = UnmodeledUse : mu* -# 135| v135_8(void) = AliasedUse : ~m139_7 -# 135| v135_9(void) = ExitFunction : +# 135| v135_5(void) = ReturnVoid : +# 135| v135_6(void) = AliasedUse : ~m139_7 +# 135| v135_7(void) = ExitFunction : # 143| void test_read_arg_different(A*) # 143| Block 0 @@ -999,37 +963,35 @@ test.cpp: # 143| valnum = unique # 143| m143_4(unknown) = Chi : total:m143_2, partial:m143_3 # 143| valnum = unique -# 143| mu143_5(unknown) = UnmodeledDefinition : -# 143| valnum = unique -# 143| r143_6(glval) = VariableAddress[pa] : -# 143| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 143| m143_7(A *) = InitializeParameter[pa] : &:r143_6 -# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 -# 143| r143_8(A *) = Load : &:r143_6, m143_7 -# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 -# 143| m143_9(unknown) = InitializeIndirection[pa] : &:r143_8 +# 143| r143_5(glval) = VariableAddress[pa] : +# 143| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 143| m143_6(A *) = InitializeParameter[pa] : &:r143_5 +# 143| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 +# 143| r143_7(A *) = Load : &:r143_5, m143_6 +# 143| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 +# 143| m143_8(unknown) = InitializeIndirection[pa] : &:r143_7 # 143| valnum = unique # 144| r144_1(glval) = VariableAddress[b] : # 144| valnum = unique # 144| r144_2(glval) = VariableAddress[pa] : -# 144| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 144| r144_3(A *) = Load : &:r144_2, m143_7 -# 144| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 144| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 144| r144_3(A *) = Load : &:r144_2, m143_6 +# 144| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 144| r144_4(glval) = FieldAddress[x] : r144_3 # 144| valnum = r144_4, r149_4 -# 144| r144_5(int) = Load : &:r144_4, ~m143_9 +# 144| r144_5(int) = Load : &:r144_4, ~m143_8 # 144| valnum = m144_6, m149_6, r144_5, r149_5 # 144| m144_6(int) = Store : &:r144_1, r144_5 # 144| valnum = m144_6, m149_6, r144_5, r149_5 # 145| r145_1(glval) = VariableAddress[c] : # 145| valnum = unique # 145| r145_2(glval) = VariableAddress[pa] : -# 145| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 145| r145_3(A *) = Load : &:r145_2, m143_7 -# 145| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 145| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 145| r145_3(A *) = Load : &:r145_2, m143_6 +# 145| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 145| r145_4(glval) = FieldAddress[y] : r145_3 # 145| valnum = r145_4, r147_5 -# 145| r145_5(int) = Load : &:r145_4, ~m143_9 +# 145| r145_5(int) = Load : &:r145_4, ~m143_8 # 145| valnum = m145_6, r145_5 # 145| m145_6(int) = Store : &:r145_1, r145_5 # 145| valnum = m145_6, r145_5 @@ -1038,33 +1000,32 @@ test.cpp: # 147| r147_2(int) = Load : &:r147_1, ~m143_3 # 147| valnum = m147_6, r147_2 # 147| r147_3(glval) = VariableAddress[pa] : -# 147| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 147| r147_4(A *) = Load : &:r147_3, m143_7 -# 147| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 147| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 147| r147_4(A *) = Load : &:r147_3, m143_6 +# 147| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 147| r147_5(glval) = FieldAddress[y] : r147_4 # 147| valnum = r145_4, r147_5 # 147| m147_6(int) = Store : &:r147_5, r147_2 # 147| valnum = m147_6, r147_2 -# 147| m147_7(unknown) = Chi : total:m143_9, partial:m147_6 +# 147| m147_7(unknown) = Chi : total:m143_8, partial:m147_6 # 147| valnum = unique # 149| r149_1(glval) = VariableAddress[d] : # 149| valnum = unique # 149| r149_2(glval) = VariableAddress[pa] : -# 149| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 149| r149_3(A *) = Load : &:r149_2, m143_7 -# 149| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 149| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 149| r149_3(A *) = Load : &:r149_2, m143_6 +# 149| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 149| r149_4(glval) = FieldAddress[x] : r149_3 # 149| valnum = r144_4, r149_4 -# 149| r149_5(int) = Load : &:r149_4, ~m143_9 +# 149| r149_5(int) = Load : &:r149_4, ~m143_8 # 149| valnum = m144_6, m149_6, r144_5, r149_5 # 149| m149_6(int) = Store : &:r149_1, r149_5 # 149| valnum = m144_6, m149_6, r144_5, r149_5 # 150| v150_1(void) = NoOp : -# 143| v143_10(void) = ReturnIndirection[pa] : &:r143_8, m147_7 -# 143| v143_11(void) = ReturnVoid : -# 143| v143_12(void) = UnmodeledUse : mu* -# 143| v143_13(void) = AliasedUse : m143_3 -# 143| v143_14(void) = ExitFunction : +# 143| v143_9(void) = ReturnIndirection[pa] : &:r143_7, m147_7 +# 143| v143_10(void) = ReturnVoid : +# 143| v143_11(void) = AliasedUse : m143_3 +# 143| v143_12(void) = ExitFunction : # 152| void test_read_global_different(int) # 152| Block 0 @@ -1075,12 +1036,10 @@ test.cpp: # 152| valnum = unique # 152| m152_4(unknown) = Chi : total:m152_2, partial:m152_3 # 152| valnum = unique -# 152| mu152_5(unknown) = UnmodeledDefinition : -# 152| valnum = unique -# 152| r152_6(glval) = VariableAddress[n] : -# 152| valnum = r152_6, r156_1 -# 152| m152_7(int) = InitializeParameter[n] : &:r152_6 -# 152| valnum = m152_7, m156_6, r156_2 +# 152| r152_5(glval) = VariableAddress[n] : +# 152| valnum = r152_5, r156_1 +# 152| m152_6(int) = InitializeParameter[n] : &:r152_5 +# 152| valnum = m152_6, m156_6, r156_2 # 153| r153_1(glval) = VariableAddress[b] : # 153| valnum = unique # 153| r153_2(glval) = VariableAddress[global_a] : @@ -1106,9 +1065,9 @@ test.cpp: # 154| m154_6(int) = Store : &:r154_1, r154_5 # 154| valnum = m153_6, m154_6, r153_5, r154_5 # 156| r156_1(glval) = VariableAddress[n] : -# 156| valnum = r152_6, r156_1 -# 156| r156_2(int) = Load : &:r156_1, m152_7 -# 156| valnum = m152_7, m156_6, r156_2 +# 156| valnum = r152_5, r156_1 +# 156| r156_2(int) = Load : &:r156_1, m152_6 +# 156| valnum = m152_6, m156_6, r156_2 # 156| r156_3(glval) = VariableAddress[global_a] : # 156| valnum = r153_2, r154_2, r156_3, r158_2 # 156| r156_4(A *) = Load : &:r156_3, ~m152_3 @@ -1116,7 +1075,7 @@ test.cpp: # 156| r156_5(glval) = FieldAddress[y] : r156_4 # 156| valnum = unique # 156| m156_6(int) = Store : &:r156_5, r156_2 -# 156| valnum = m152_7, m156_6, r156_2 +# 156| valnum = m152_6, m156_6, r156_2 # 156| m156_7(unknown) = Chi : total:m152_4, partial:m156_6 # 156| valnum = unique # 158| r158_1(glval) = VariableAddress[d] : @@ -1132,7 +1091,6 @@ test.cpp: # 158| m158_6(int) = Store : &:r158_1, r158_5 # 158| valnum = m158_6, r158_5 # 159| v159_1(void) = NoOp : -# 152| v152_8(void) = ReturnVoid : -# 152| v152_9(void) = UnmodeledUse : mu* -# 152| v152_10(void) = AliasedUse : ~m156_7 -# 152| v152_11(void) = ExitFunction : +# 152| v152_7(void) = ReturnVoid : +# 152| v152_8(void) = AliasedUse : ~m156_7 +# 152| v152_9(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected b/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected index e051dc37506..fa7208639c6 100644 --- a/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected +++ b/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected @@ -58,7 +58,7 @@ | test.cpp:129:13:129:17 | array to pointer conversion | 125:c20-c24 126:c20-c24 129:c13-c17 | | test.cpp:129:13:129:17 | bar | 125:c20-c24 126:c20-c24 129:c13-c17 | | test.cpp:141:12:141:17 | call to getInt | 141:c12-c17 141:c29-c34 | -| test.cpp:141:23:141:26 | this | 0:c0-c0 141:c23-c26 | +| test.cpp:141:12:141:17 | this | 141:c12-c17 141:c23-c26 | | test.cpp:146:10:146:11 | ih | 146:c10-c11 146:c31-c32 | | test.cpp:146:13:146:25 | call to getDoubledInt | 146:c13-c25 146:c34-c46 | | test.cpp:150:3:150:3 | x | 150:c3-c3 150:c9-c9 151:c3-c3 151:c9-c9 152:c12-c12 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c index f1d08648224..9c56fda859c 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c @@ -363,4 +363,22 @@ int callCommand(void) if (tmp == 1) // tmp could have been modified by the call. return 1; return 0; -} \ No newline at end of file +} + +int shifts(void) +{ + unsigned int x = 3; + + if (x >> 1 >= 1) {} // always true + if (x >> 1 >= 2) {} // always false + if (x >> 1 == 1) {} // always true [NOT DETECTED] +} + +int bitwise_ands() +{ + unsigned int x = 0xFF; + + if ((x & 2) >= 1) {} + if ((x & 2) >= 2) {} + if ((x & 2) >= 3) {} // always false +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp index 67fcfd7b049..7b67f77ad44 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp @@ -26,4 +26,20 @@ void test1() { if(a.int_member <= 10) {} if(volatile_const_global <= 10) {} -} \ No newline at end of file +} + +int extreme_values(void) +{ + unsigned long long int x = 0xFFFFFFFFFFFFFFFF; + unsigned long long int y = 0xFFFFFFFFFFFF; + + if (x >> 1 >= 0xFFFFFFFFFFFFFFFF) {} // always false + if (x >> 1 >= 0x8000000000000000) {} // always false [NOT DETECTED] + if (x >> 1 >= 0x7FFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] + if (x >> 1 >= 0xFFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] + + if (y >> 1 >= 0xFFFFFFFFFFFF) {} // always false [INCORRECT MESSAGE] + if (y >> 1 >= 0x800000000000) {} // always false [INCORRECT MESSAGE] + if (y >> 1 >= 0x7FFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] + if (y >> 1 >= 0xFFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index 55b06bc4b01..c2c6cf6f14d 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -38,5 +38,13 @@ | PointlessComparison.c:303:9:303:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:312:9:312:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:337:14:337:21 | ... >= ... | Comparison is always true because x >= 0. | +| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1. | +| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1. | +| PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | +| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. | +| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | +| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | +| PointlessComparison.cpp:43:6:43:29 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | +| PointlessComparison.cpp:44:6:44:28 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | | RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. | | Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index f84c6719157..5c46a7c8193 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -7,6 +7,22 @@ edges | test.cpp:42:18:42:34 | (const char *)... | test.cpp:24:30:24:36 | command | | test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command | | test.cpp:43:18:43:34 | (const char *)... | test.cpp:29:30:29:36 | command | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | (const char *)... | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | (const char *)... | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | (const char *)... | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | (const char *)... | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | (const char *)... | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | (const char *)... | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | (const char *)... | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | nodes | test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | @@ -20,6 +36,26 @@ nodes | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | | test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv | | test.cpp:43:18:43:34 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:56:12:56:17 | buffer | semmle.label | buffer | +| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | +| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:63:10:63:13 | data | semmle.label | data | +| test.cpp:76:12:76:17 | buffer | semmle.label | buffer | +| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | +| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:79:10:79:13 | data | semmle.label | data | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | +| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | +| test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index 83a67f44417..eb9436bcadb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp @@ -42,3 +42,42 @@ void testMyDerived() md2->doCommand2(getenv("varname")); md3->doCommand3(getenv("varname")); } + +// --- + +typedef struct {} FILE; +char *fgets(char *s, int n, FILE *stream); +FILE *stdin; + +void testReferencePointer1() +{ + char buffer[1024]; + + if (fgets(buffer, 1024, stdin) != 0) + { + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} + +void testReferencePointer2() +{ + char buffer[1024]; + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + if (fgets(buffer, 1024, stdin) != 0) + { + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index 0064b6d5715..1d92afdeb04 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -53,6 +53,8 @@ edges | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | @@ -63,6 +65,8 @@ edges | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | @@ -77,9 +81,11 @@ edges | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:117:15:117:16 | Argument 0 indirection | argvLocal.c:117:15:117:16 | printWrapper output argument | | argvLocal.c:117:15:117:16 | array to pointer conversion | argvLocal.c:117:15:117:16 | printWrapper output argument | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | (const char *)... | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | Argument 0 indirection | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | @@ -87,6 +93,7 @@ edges | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:122:15:122:16 | Argument 0 indirection | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:122:15:122:16 | i4 | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | | argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | @@ -96,6 +103,8 @@ edges | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | (const char *)... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | @@ -110,6 +119,7 @@ edges | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:128:15:128:16 | Argument 0 indirection | argvLocal.c:128:15:128:16 | printWrapper output argument | | argvLocal.c:128:15:128:16 | array to pointer conversion | argvLocal.c:128:15:128:16 | printWrapper output argument | | argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | (const char *)... | | argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... | @@ -156,8 +166,10 @@ edges | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | nodes +| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct | | argvLocal.c:9:25:9:31 | correct | semmle.label | correct | | argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi | +| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... | @@ -203,6 +215,7 @@ nodes | argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 | +| argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 | @@ -210,6 +223,7 @@ nodes | argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | +| argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | @@ -219,6 +233,7 @@ nodes | argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 | +| argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 773a969e9ad..8aa79b5bb6d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,6 +59,26 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | +| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | nodes | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | @@ -122,6 +142,32 @@ nodes | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:241:2:241:32 | Chi | semmle.label | Chi | +| test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | +| test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | +| test.cpp:249:20:249:33 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:301:19:301:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:309:19:309:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | #select | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | @@ -136,3 +182,8 @@ nodes | test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | +| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | +| test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (getenv) | +| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (getenv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c new file mode 100644 index 00000000000..9a69a420a79 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -0,0 +1,21 @@ +int atoi(const char *nptr); +void *malloc(unsigned long size); +char *getenv(const char *name); + + +struct XY { + int x; + int y; +}; + +void taint_array(struct XY *xyp) { + int tainted = atoi(getenv("VAR")); + xyp->y = tainted; +} + +void test_conflated_fields3(void) { + struct XY xy; + xy.x = 4; + taint_array(&xy); + malloc(xy.x); // not tainted +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index cb21e8f1915..0683f7211e3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -236,3 +236,81 @@ void more_cases() { my_func(100); // GOOD my_func(local_size); // GOOD } + +bool get_size(int &out_size) { + out_size = atoi(getenv("USER")); + + return true; +} + +void equality_cases() { + { + int size1 = atoi(getenv("USER")); + int size2 = atoi(getenv("USER")); + + if (size1 == 100) + { + malloc(size2 * sizeof(int)); // BAD + } + if (size2 == 100) + { + malloc(size2 * sizeof(int)); // GOOD + } + } + { + int size = atoi(getenv("USER")); + + if (size != 100) + return; + + malloc(size * sizeof(int)); // GOOD + } + { + int size; + + if ((get_size(size)) && (size == 100)) + { + malloc(size * sizeof(int)); // GOOD + } + } + { + int size; + + if ((get_size(size)) && (size != 100)) + { + malloc(size * sizeof(int)); // BAD + } + } + { + int size; + + if ((!get_size(size)) || (size != 100)) + return; + + malloc(size * sizeof(int)); // GOOD + } + { + int size; + + if ((!get_size(size)) || (size == 100)) + return; + + malloc(size * sizeof(int)); // BAD + } + { + int size = atoi(getenv("USER")); + + if ((size == 50) || (size == 100)) + { + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size = atoi(getenv("USER")); + + if (size != 50 && size != 100) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected index 20e5eafbd3b..a46371f36b6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected @@ -5,5 +5,4 @@ | test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value | | test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | | test.c:76:3:76:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | -| test.c:114:9:114:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:108:17:108:23 | 2147483647 | Extreme value | | test.c:124:9:124:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:118:17:118:23 | 2147483647 | Extreme value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c index e17d413e3fd..8c40d984ee0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c @@ -111,7 +111,7 @@ void test_guards3(int cond) { if (x != 0) return; - return x + 1; // GOOD [FALSE POSITIVE] + return x + 1; // GOOD } void test_guards4(int cond) { diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected new file mode 100644 index 00000000000..f514742ff0a --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected @@ -0,0 +1,3 @@ +| test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked | +| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked | +| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref new file mode 100644 index 00000000000..c7d2e9c45f4 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-367/TOCTOUFilesystemRace.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp new file mode 100644 index 00000000000..b876146f571 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp @@ -0,0 +1,51 @@ + +class String +{ +public: + String(const char *_s); + void set(const char *_s); +}; + +void create(const String &filename); +bool rename(const String &from, const String &to); +void remove(const String &filename); + +void test1() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + + create(file1); + if (!rename(file1, file2)) + { + remove(file1); // BAD + } +} + + +void test2() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + + create(file1); + if (!rename(file1, file2)) + { + file1.set("d.txt"); + remove(file1); // GOOD [FALSE POSITIVE] + } +} + + +void test3() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + file1.set("d.txt"); + + create(file1); + if (!rename(file1, file2)) + { + remove(file1); // BAD + } +} diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme new file mode 100644 index 00000000000..2074f1cc7a3 --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme @@ -0,0 +1,2100 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..282c13bfdbc --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties new file mode 100644 index 00000000000..8f171d51e9f --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties @@ -0,0 +1,2 @@ +description: Add union types for casts and accesses +compatibility: full diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql new file mode 100644 index 00000000000..2e99f1ed5f0 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql @@ -0,0 +1,48 @@ +/* + * Upgrade script to populate the member_function_this_type table. It's a rough + * approximation of what the extractor would do - for a member function C::f, + * we say its type is C* (if that pointer type exists in the database). + * CV-qualifiers are ignored. + */ + +class Class extends @usertype { + Class() { + usertypes(this, _, 1) or + usertypes(this, _, 2) or + usertypes(this, _, 3) or + usertypes(this, _, 6) or + usertypes(this, _, 10) or + usertypes(this, _, 11) or + usertypes(this, _, 12) + } + + string toString() { usertypes(this, result, _) } +} + +class ClassPointerType extends @derivedtype { + ClassPointerType() { derivedtypes(this, _, 1, _) } + + Class getBaseType() { derivedtypes(this, _, _, result) } + + string toString() { result = getBaseType().toString() + "*" } +} + +class DefinedMemberFunction extends @function { + DefinedMemberFunction() { + exists(@fun_decl fd | + fun_def(fd) and + ( + fun_decls(fd, this, _, _, _) + or + exists(@function f | function_instantiation(this, f) and fun_decls(fd, f, _, _, _)) + ) + ) + } + + ClassPointerType getTypeOfThis() { member(result.getBaseType(), _, this) } + + string toString() { functions(this, result, _) } +} + +from DefinedMemberFunction f +select f, f.getTypeOfThis() diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme new file mode 100644 index 00000000000..282c13bfdbc --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..025827d85c3 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties new file mode 100644 index 00000000000..018a42e6dc1 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties @@ -0,0 +1,3 @@ +description: Add table relating a member function to the type of `this`. +compatibility: partial +member_function_this_type.rel: run member_function_this_type.qlo diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme new file mode 100644 index 00000000000..874439f4c50 --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme @@ -0,0 +1,2039 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..2074f1cc7a3 --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme @@ -0,0 +1,2100 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties new file mode 100644 index 00000000000..4cfa3249130 --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties @@ -0,0 +1,2 @@ +description: Add some unions to the dbscheme +compatibility: full diff --git a/csharp/CSharp.sln b/csharp/CSharp.sln index 78d853a5bbe..7762dd469b9 100644 --- a/csharp/CSharp.sln +++ b/csharp/CSharp.sln @@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL", "extractor\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj", "{399A1579-68F0-40F4-9A23-F241BA697F9C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild", "autobuilder\Semmle.Autobuild\Semmle.Autobuild.csproj", "{5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Standalone", "extractor\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj", "{D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL.Driver", "extractor\Semmle.Extraction.CIL.Driver\Semmle.Extraction.CIL.Driver.csproj", "{EFA400B3-C1CE-446F-A4E2-8B44E61EF47C}" @@ -23,7 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.Tests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Util.Tests", "extractor\Semmle.Util.Tests\Semmle.Util.Tests.csproj", "{55A620F0-23F6-440D-A5BA-0567613B3C0F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild.Tests", "autobuilder\Semmle.Autobuild.Tests\Semmle.Autobuild.Tests.csproj", "{CE267461-D762-4F53-A275-685A0A4EC48D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.Shared", "autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj", "{133F2B5B-FD25-4BD9-B34C-062CC6BB4178}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp", "autobuilder\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj", "{F3C07863-3759-4A0B-B777-8A0E0FDB1A41}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp.Tests", "autobuilder\Semmle.Autobuild.CSharp.Tests\Semmle.Autobuild.CSharp.Tests.csproj", "{34256E8F-866A-46C1-800E-3DF69FD1DCB7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,10 +49,6 @@ Global {399A1579-68F0-40F4-9A23-F241BA697F9C}.Debug|Any CPU.Build.0 = Debug|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.ActiveCfg = Release|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.Build.0 = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.Build.0 = Release|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -69,10 +67,18 @@ Global {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.Build.0 = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.Build.0 = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.Build.0 = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.Build.0 = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs similarity index 89% rename from csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index ebd925b4778..5c6441a7df0 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -1,12 +1,12 @@ using Xunit; -using Semmle.Autobuild; +using Semmle.Autobuild.Shared; using System.Collections.Generic; using System; using System.Linq; using Microsoft.Build.Construction; using System.Xml; -namespace Semmle.Extraction.Tests +namespace Semmle.Autobuild.CSharp.Tests { /// /// Test class to script Autobuilder scenarios. @@ -44,7 +44,7 @@ namespace Semmle.Extraction.Tests public IDictionary RunProcessOut = new Dictionary(); public IDictionary RunProcessWorkingDirectory = new Dictionary(); - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env, out IList stdOut) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); @@ -60,7 +60,7 @@ namespace Semmle.Extraction.Tests throw new ArgumentException("Missing RunProcess " + pattern); } - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); @@ -80,26 +80,24 @@ namespace Semmle.Extraction.Tests } public IDictionary DirectoryExists = new Dictionary(); - public IList DirectoryExistsIn = new List(); bool IBuildActions.DirectoryExists(string dir) { - DirectoryExistsIn.Add(dir); if (DirectoryExists.TryGetValue(dir, out var ret)) return ret; throw new ArgumentException("Missing DirectoryExists " + dir); } - public IDictionary GetEnvironmentVariable = new Dictionary(); + public IDictionary GetEnvironmentVariable = new Dictionary(); - string IBuildActions.GetEnvironmentVariable(string name) + string? IBuildActions.GetEnvironmentVariable(string name) { if (GetEnvironmentVariable.TryGetValue(name, out var ret)) return ret; throw new ArgumentException("Missing GetEnvironmentVariable " + name); } - public string GetCurrentDirectory; + public string GetCurrentDirectory = ""; string IBuildActions.GetCurrentDirectory() { @@ -333,21 +331,21 @@ namespace Semmle.Extraction.Tests Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(Actions, StartCallback, EndCallback)); } - Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows, - string buildless = null, string solution = null, string buildCommand = null, string ignoreErrors = null, - string msBuildArguments = null, string msBuildPlatform = null, string msBuildConfiguration = null, string msBuildTarget = null, - string dotnetArguments = null, string dotnetVersion = null, string vsToolsVersion = null, - string nugetRestore = null, string allSolutions = null, + CSharpAutobuilder CreateAutoBuilder(bool isWindows, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, string cwd = @"C:\Project") { - Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false"; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp"; + string codeqlUpperLanguage = Language.CSharp.UpperCaseName; + Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; - Actions.GetEnvironmentVariable["LGTM_PROJECT_LANGUAGE"] = lgtmLanguage; Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; @@ -366,8 +364,8 @@ namespace Semmle.Extraction.Tests Actions.GetCurrentDirectory = cwd; Actions.IsWindows = isWindows; - var options = new AutobuildOptions(Actions); - return new Autobuilder(Actions, options); + var options = new AutobuildOptions(Actions, Language.CSharp); + return new CSharpAutobuilder(Actions, options); } [Fact] @@ -395,7 +393,7 @@ namespace Semmle.Extraction.Tests "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", true); + var autobuilder = CreateAutoBuilder(true); TestAutobuilderScript(autobuilder, 0, 6); } @@ -427,7 +425,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 7); } @@ -440,47 +438,10 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 0); } - - [Fact] - public void TestDefaultCppAutobuilder() - { - Actions.EnumerateFiles[@"C:\Project"] = ""; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var script = autobuilder.GetBuildScript(); - - // Fails due to no solutions present. - Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); - } - - [Fact] - public void TestCppAutobuilderSuccess() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; - Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var solution = new TestSolution(@"C:\Project\test.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(solution); - TestAutobuilderScript(autobuilder, 0, 2); - } - [Fact] public void TestVsWhereSucceeded() { @@ -537,7 +498,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); + var autobuilder = CreateAutoBuilder(false, buildless: "true"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -551,7 +512,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); + var autobuilder = CreateAutoBuilder(false, buildless: "true"); TestAutobuilderScript(autobuilder, 10, 1); } @@ -567,7 +528,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln"); + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -615,7 +576,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap SkipVsWhere(); - var autobuilder = CreateAutoBuilder("csharp", false, buildCommand: "./build.sh --skip-tests"); + var autobuilder = CreateAutoBuilder(false, buildCommand: "./build.sh --skip-tests"); TestAutobuilderScript(autobuilder, 0, 4); } @@ -635,7 +596,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 5); } @@ -654,7 +615,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; Actions.FileExists["csharp.log"] = false; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 3); } @@ -673,7 +634,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 3); } @@ -690,7 +651,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", true); + var autobuilder = CreateAutoBuilder(true); TestAutobuilderScript(autobuilder, 0, 3); } @@ -707,7 +668,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", true, ignoreErrors: "true"); + var autobuilder = CreateAutoBuilder(true, ignoreErrors: "true"); TestAutobuilderScript(autobuilder, 1, 1); } @@ -725,7 +686,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); + var autobuilder = CreateAutoBuilder(true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); TestAutobuilderScript(autobuilder, 3, 1); } @@ -750,7 +711,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); @@ -801,7 +762,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test2.csproj"] = csproj2; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12"); TestAutobuilderScript(autobuilder, 0, 6); @@ -823,7 +784,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); @@ -852,7 +813,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true", nugetRestore: "false"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); @@ -875,7 +836,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -908,7 +869,7 @@ Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. + var autobuilder = CreateAutoBuilder(false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. TestAutobuilderScript(autobuilder, 0, 7); } @@ -947,7 +908,7 @@ Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 12); } @@ -989,7 +950,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 12); } @@ -1023,7 +984,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(true, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 9); } @@ -1065,7 +1026,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["dirs.proj"] = dirsproj; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); TestAutobuilderScript(autobuilder, 0, 4); } @@ -1102,7 +1063,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["dirs.proj"] = dirsproj; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 4); } @@ -1124,7 +1085,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap "); Actions.LoadXml["dirs.proj"] = dirsproj1; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 0); } diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj similarity index 78% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj index 547aaa570b4..be45ad8f961 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj @@ -5,6 +5,7 @@ netcoreapp3.0 false win-x64;linux-x64;osx-x64 + enable @@ -18,7 +19,7 @@ - + + - diff --git a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs similarity index 90% rename from csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs index f9c690c273b..2f69faeafde 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// /// ASP extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs new file mode 100644 index 00000000000..647a3ad2b4d --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs @@ -0,0 +1,127 @@ +using Semmle.Extraction.CSharp; +using Semmle.Util.Logging; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + public class CSharpAutobuilder : Autobuilder + { + public CSharpAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + /// + /// A script that checks that the C# extractor has been executed. + /// + BuildScript CheckExtractorRun(bool warnOnFailure) => + BuildScript.Create(actions => + { + if (actions.FileExists(Extractor.GetCSharpLogPath())) + return 0; + + if (warnOnFailure) + Log(Severity.Error, "No C# code detected during build."); + + return 1; + }); + + var attempt = BuildScript.Failure; + switch (GetCSharpBuildStrategy()) + { + case CSharpBuildStrategy.CustomBuildCommand: + attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Buildless: + // No need to check that the extractor has been executed in buildless mode + attempt = new StandaloneBuildRule().Analyse(this, false); + break; + case CSharpBuildStrategy.MSBuild: + attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.DotNet: + attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Auto: + var cleanTrapFolder = + BuildScript.DeleteDirectory(TrapDir); + var cleanSourceArchive = + BuildScript.DeleteDirectory(SourceArchiveDir); + var tryCleanExtractorArgsLogs = + BuildScript.Create(actions => + { + foreach (var file in Extractor.GetCSharpArgsLogs()) + try + { + actions.FileDelete(file); + } + catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] + { } + return 0; + }); + var attemptExtractorCleanup = + BuildScript.Try(cleanTrapFolder) & + BuildScript.Try(cleanSourceArchive) & + tryCleanExtractorArgsLogs & + BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); + + /// + /// Execute script `s` and check that the C# extractor has been executed. + /// If either fails, attempt to cleanup any artifacts produced by the extractor, + /// and exit with code 1, in order to proceed to the next attempt. + /// + BuildScript IntermediateAttempt(BuildScript s) => + (s & CheckExtractorRun(false)) | + (attemptExtractorCleanup & BuildScript.Failure); + + attempt = + // First try .NET Core + IntermediateAttempt(new DotNetRule().Analyse(this, true)) | + // Then MSBuild + (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | + // And finally look for a script that might be a build script + (() => new BuildCommandAutoRule(DotNetRule.WithDotNet).Analyse(this, true) & CheckExtractorRun(true)) | + // All attempts failed: print message + AutobuildFailure(); + break; + } + + return + attempt & + (() => new AspBuildRule().Analyse(this, false)) & + (() => new XmlBuildRule().Analyse(this, false)); + } + + /// + /// Gets the build strategy that the autobuilder should apply, based on the + /// options in the `lgtm.yml` file. + /// + CSharpBuildStrategy GetCSharpBuildStrategy() + { + if (Options.BuildCommand != null) + return CSharpBuildStrategy.CustomBuildCommand; + + if (Options.Buildless) + return CSharpBuildStrategy.Buildless; + + if (Options.MsBuildArguments != null + || Options.MsBuildConfiguration != null + || Options.MsBuildPlatform != null + || Options.MsBuildTarget != null) + return CSharpBuildStrategy.MSBuild; + + if (Options.DotNetArguments != null || Options.DotNetVersion != null) + return CSharpBuildStrategy.DotNet; + + return CSharpBuildStrategy.Auto; + } + + enum CSharpBuildStrategy + { + CustomBuildCommand, + Buildless, + MSBuild, + DotNet, + Auto + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index 21215af8434..2d365f961da 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -6,8 +6,9 @@ using System.Collections.Generic; using System.IO; using Semmle.Util; using System.Text.RegularExpressions; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.CSharp { /// /// A build rule where the build command is of the form "dotnet build". diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs new file mode 100644 index 00000000000..ecefdd0efb2 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs @@ -0,0 +1,33 @@ +using System; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + class Program + { + static int Main() + { + + try + { + var actions = SystemBuildActions.Instance; + var options = new AutobuildOptions(actions, Language.CSharp); + try + { + Console.WriteLine("CodeQL C# autobuilder"); + var builder = new CSharpAutobuilder(actions, options); + return builder.AttemptBuild(); + } + catch (InvalidEnvironmentException ex) + { + Console.WriteLine("The environment is invalid: {0}", ex.Message); + } + } + catch (ArgumentOutOfRangeException ex) + { + Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName); + } + return 1; + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..7314539ace4 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Semmle.Autobuild.CSharp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C#")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj similarity index 79% rename from csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index 63aab3b29fb..091f0704ef0 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -2,8 +2,8 @@ netcoreapp3.0 - Semmle.Autobuild - Semmle.Autobuild + Semmle.Autobuild.CSharp + Semmle.Autobuild.CSharp Exe @@ -24,6 +24,7 @@ + diff --git a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs similarity index 95% rename from csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs index 26bc84bb601..5bfc8c776c4 100644 --- a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// /// Build using standalone extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs similarity index 88% rename from csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs index d9b05dbe0a9..d262ec1f20b 100644 --- a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// /// XML extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs similarity index 84% rename from csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs index 9786e4dcca6..28c14be13ff 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text.RegularExpressions; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Encapsulates build options. @@ -35,7 +35,7 @@ namespace Semmle.Autobuild /// Reads options from environment variables. /// Throws ArgumentOutOfRangeException for invalid arguments. /// - public AutobuildOptions(IBuildActions actions) + public AutobuildOptions(IBuildActions actions, Language language) { RootDirectory = actions.GetCurrentDirectory(); VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION"); @@ -53,8 +53,9 @@ namespace Semmle.Autobuild AllSolutions = actions.GetEnvironmentVariable(prefix + "ALL_SOLUTIONS").AsBool("all_solutions", false); NugetRestore = actions.GetEnvironmentVariable(prefix + "NUGET_RESTORE").AsBool("nuget_restore", true); - Language = actions.GetEnvironmentVariable("LGTM_PROJECT_LANGUAGE").AsLanguage(); - Indexing = !actions.GetEnvironmentVariable("CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING").AsBool("no_indexing", false); + Language = language; + + Indexing = !actions.GetEnvironmentVariable($"CODEQL_AUTOBUILDER_{Language.UpperCaseName}_NO_INDEXING").AsBool("no_indexing", false); } } @@ -80,21 +81,6 @@ namespace Semmle.Autobuild } } - public static Language AsLanguage(this string? key) - { - switch (key) - { - case null: - throw new ArgumentException("Environment variable required: LGTM_PROJECT_LANGUAGE"); - case "csharp": - return Language.CSharp; - case "cpp": - return Language.Cpp; - default: - throw new ArgumentException("Language key not understood: '" + key + "'"); - } - } - public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActions actions, string[] defaultValue) { if (value == null) diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs similarity index 58% rename from csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs index a882f5bb80c..e3889c550c9 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs @@ -1,16 +1,15 @@ -using Semmle.Extraction.CSharp; -using Semmle.Util.Logging; +using Semmle.Util.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A build rule analyses the files in "builder" and outputs a build script. /// - interface IBuildRule + public interface IBuildRule { /// /// Analyse the files and produce a build script. @@ -23,7 +22,7 @@ namespace Semmle.Autobuild /// /// Exception indicating that environment variables are missing or invalid. /// - class InvalidEnvironmentException : Exception + public class InvalidEnvironmentException : Exception { public InvalidEnvironmentException(string m) : base(m) { } } @@ -35,7 +34,7 @@ namespace Semmle.Autobuild /// The overall design is intended to be extensible so that in theory, /// it should be possible to add new build rules without touching this code. /// - public class Autobuilder + public abstract class Autobuilder { /// /// Full file paths of files found in the project directory, as well as @@ -126,10 +125,10 @@ namespace Semmle.Autobuild ToArray(); if (matchingFiles.Length == 0) - return null; + return null; if (Options.AllSolutions) - return matchingFiles.Select(p => p.ProjectOrSolution); + return matchingFiles.Select(p => p.ProjectOrSolution); return matchingFiles. Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot). @@ -184,34 +183,34 @@ namespace Semmle.Autobuild return ret ?? new List(); }); - CodeQLExtractorCSharpRoot = Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_ROOT"); + CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT"); SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); - JavaHome = + JavaHome = Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ?? - Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? + Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set."); Distribution = - CodeQLExtractorCSharpRoot ?? + CodeQLExtractorLangRoot ?? SemmleDist ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT or SEMMLE_DIST has not been set."); TrapDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ?? Actions.GetEnvironmentVariable("TRAP_FOLDER") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_TRAP_DIR or TRAP_FOLDER has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR or TRAP_FOLDER has not been set."); SourceArchiveDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ?? Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); } - private string TrapDir { get; } + protected string TrapDir { get; } - private string SourceArchiveDir { get; } + protected string SourceArchiveDir { get; } readonly ILogger logger = new ConsoleLogger(Verbosity.Info); @@ -234,6 +233,7 @@ namespace Semmle.Autobuild Log(Severity.Info, $"Working directory: {Options.RootDirectory}"); var script = GetBuildScript(); + if (Options.IgnoreErrors) script |= BuildScript.Success; @@ -253,143 +253,9 @@ namespace Semmle.Autobuild /// /// Returns the build script to use for this project. /// - public BuildScript GetBuildScript() - { - var isCSharp = Options.Language == Language.CSharp; - return isCSharp ? GetCSharpBuildScript() : GetCppBuildScript(); - } + public abstract BuildScript GetBuildScript(); - BuildScript GetCSharpBuildScript() - { - /// - /// A script that checks that the C# extractor has been executed. - /// - BuildScript CheckExtractorRun(bool warnOnFailure) => - BuildScript.Create(actions => - { - if (actions.FileExists(Extractor.GetCSharpLogPath())) - return 0; - - if (warnOnFailure) - Log(Severity.Error, "No C# code detected during build."); - - return 1; - }); - - var attempt = BuildScript.Failure; - switch (GetCSharpBuildStrategy()) - { - case CSharpBuildStrategy.CustomBuildCommand: - attempt = new BuildCommandRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Buildless: - // No need to check that the extractor has been executed in buildless mode - attempt = new StandaloneBuildRule().Analyse(this, false); - break; - case CSharpBuildStrategy.MSBuild: - attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.DotNet: - attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Auto: - var cleanTrapFolder = - BuildScript.DeleteDirectory(TrapDir); - var cleanSourceArchive = - BuildScript.DeleteDirectory(SourceArchiveDir); - var tryCleanExtractorArgsLogs = - BuildScript.Create(actions => - { - foreach (var file in Extractor.GetCSharpArgsLogs()) - try - { - actions.FileDelete(file); - } - catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] - { } - return 0; - }); - var attemptExtractorCleanup = - BuildScript.Try(cleanTrapFolder) & - BuildScript.Try(cleanSourceArchive) & - tryCleanExtractorArgsLogs & - BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); - - /// - /// Execute script `s` and check that the C# extractor has been executed. - /// If either fails, attempt to cleanup any artifacts produced by the extractor, - /// and exit with code 1, in order to proceed to the next attempt. - /// - BuildScript IntermediateAttempt(BuildScript s) => - (s & CheckExtractorRun(false)) | - (attemptExtractorCleanup & BuildScript.Failure); - - attempt = - // First try .NET Core - IntermediateAttempt(new DotNetRule().Analyse(this, true)) | - // Then MSBuild - (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | - // And finally look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true) & CheckExtractorRun(true)) | - // All attempts failed: print message - AutobuildFailure(); - break; - } - - return - attempt & - (() => new AspBuildRule().Analyse(this, false)) & - (() => new XmlBuildRule().Analyse(this, false)); - } - - /// - /// Gets the build strategy that the autobuilder should apply, based on the - /// options in the `lgtm.yml` file. - /// - CSharpBuildStrategy GetCSharpBuildStrategy() - { - if (Options.BuildCommand != null) - return CSharpBuildStrategy.CustomBuildCommand; - - if (Options.Buildless) - return CSharpBuildStrategy.Buildless; - - if (Options.MsBuildArguments != null - || Options.MsBuildConfiguration != null - || Options.MsBuildPlatform != null - || Options.MsBuildTarget != null) - return CSharpBuildStrategy.MSBuild; - - if (Options.DotNetArguments != null || Options.DotNetVersion != null) - return CSharpBuildStrategy.DotNet; - - return CSharpBuildStrategy.Auto; - } - - enum CSharpBuildStrategy - { - CustomBuildCommand, - Buildless, - MSBuild, - DotNet, - Auto - } - - BuildScript GetCppBuildScript() - { - if (Options.BuildCommand != null) - return new BuildCommandRule().Analyse(this, false); - - return - // First try MSBuild - new MsBuildRule().Analyse(this, true) | - // Then look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true)) | - // All attempts failed: print message - AutobuildFailure(); - } - - BuildScript AutobuildFailure() => + protected BuildScript AutobuildFailure() => BuildScript.Create(actions => { Log(Severity.Error, "Could not auto-detect a suitable build method"); @@ -397,9 +263,9 @@ namespace Semmle.Autobuild }); /// - /// Value of CODEQL_EXTRACTOR_CSHARP_ROOT environment variable. + /// Value of CODEQL_EXTRACTOR__ROOT environment variable. /// - private string? CodeQLExtractorCSharpRoot { get; } + private string? CodeQLExtractorLangRoot { get; } /// /// Value of SEMMLE_DIST environment variable. @@ -426,6 +292,6 @@ namespace Semmle.Autobuild /// an odasa --index, unless indexing has been disabled, in which case /// is run directly. /// - internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); + public CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/BuildActions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index 7bc4b9b7591..63cfc3b8145 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using System.IO; using System.Xml; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Wrapper around system calls so that the build scripts can be unit-tested. @@ -124,7 +124,7 @@ namespace Semmle.Autobuild /// /// An implementation of IBuildActions that actually performs the requested operations. /// - class SystemBuildActions : IBuildActions + public class SystemBuildActions : IBuildActions { void IBuildActions.FileDelete(string file) => File.Delete(file); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs similarity index 78% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs index 80a819f403e..2ef98609512 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs @@ -1,15 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Auto-detection of build scripts. /// - class BuildCommandAutoRule : IBuildRule + public class BuildCommandAutoRule : IBuildRule { + private readonly Func?, BuildScript>, BuildScript> withDotNet; + + public BuildCommandAutoRule(Func?, BuildScript>, BuildScript> withDotNet) + { + this.withDotNet = withDotNet; + } + readonly IEnumerable winExtensions = new List { ".bat", ".cmd", @@ -43,7 +51,7 @@ namespace Semmle.Autobuild string? dir = Path.GetDirectoryName(scriptPath); // A specific .NET Core version may be required - return chmodScript & DotNetRule.WithDotNet(builder, environment => + return chmodScript & withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, dir, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs similarity index 64% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs index fe91503ec8f..79cdd8c01de 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs @@ -1,17 +1,27 @@ -namespace Semmle.Autobuild +using System; +using System.Collections.Generic; + +namespace Semmle.Autobuild.Shared { /// /// Execute the build_command rule. /// - class BuildCommandRule : IBuildRule + public class BuildCommandRule : IBuildRule { + private readonly Func?, BuildScript>, BuildScript> withDotNet; + + public BuildCommandRule(Func?, BuildScript>, BuildScript> withDotNet) + { + this.withDotNet = withDotNet; + } + public BuildScript Analyse(Autobuilder builder, bool auto) { if (builder.Options.BuildCommand == null) return BuildScript.Failure; // Custom build commands may require a specific .NET Core version - return DotNetRule.WithDotNet(builder, environment => + return withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, null, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs similarity index 97% rename from csharp/autobuilder/Semmle.Autobuild/BuildScript.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs index 5c60f4110ba..a3ac5b5cbae 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A build script. @@ -61,7 +61,7 @@ namespace Semmle.Autobuild /// Whether this command should run silently. /// The working directory (null for current directory). /// Additional environment variables. - public BuildCommand(string exe, string argumentsOpt, bool silent, string? workingDirectory = null, IDictionary? environment = null) + public BuildCommand(string exe, string? argumentsOpt, bool silent, string? workingDirectory = null, IDictionary? environment = null) { this.exe = exe; this.arguments = argumentsOpt ?? ""; @@ -183,7 +183,7 @@ namespace Semmle.Autobuild /// Whether the executable should run silently. /// The working directory (null for current directory). /// Additional environment variables. - public static BuildScript Create(string exe, string argumentsOpt, bool silent, string? workingDirectory, IDictionary? environment) => + public static BuildScript Create(string exe, string? argumentsOpt, bool silent, string? workingDirectory, IDictionary? environment) => new BuildCommand(exe, argumentsOpt, silent, workingDirectory, environment); /// diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/BuildTools.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index ca9285d2c9c..d1aab3c4551 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A BAT file used to initialise the appropriate diff --git a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs index 353f132c6ec..ef6eb951449 100644 --- a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Utility to construct a build command. /// - class CommandBuilder + public class CommandBuilder { enum EscapeMode { Process, Cmd }; diff --git a/csharp/autobuilder/Semmle.Autobuild/Language.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs similarity index 72% rename from csharp/autobuilder/Semmle.Autobuild/Language.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs index 5049506be57..c27f42fb7a7 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Language.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs @@ -1,18 +1,20 @@ -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { public sealed class Language { - public static readonly Language Cpp = new Language(".vcxproj"); - public static readonly Language CSharp = new Language(".csproj"); + public static readonly Language Cpp = new Language(".vcxproj", "CPP"); + public static readonly Language CSharp = new Language(".csproj", "CSHARP"); public bool ProjectFileHasThisLanguage(string path) => System.IO.Path.GetExtension(path) == ProjectExtension; public readonly string ProjectExtension; + public readonly string UpperCaseName; - private Language(string extension) + private Language(string extension, string name) { ProjectExtension = extension; + UpperCaseName = name; } public override string ToString() => diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 569f9f183eb..4994eefab06 100644 --- a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -1,12 +1,12 @@ using Semmle.Util.Logging; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A build rule using msbuild. /// - class MsBuildRule : IBuildRule + public class MsBuildRule : IBuildRule { /// /// The name of the msbuild command. diff --git a/csharp/autobuilder/Semmle.Autobuild/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/Project.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index 415ddcbc0f0..df8fc077145 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Xml; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Representation of a .proj file, a .csproj file (C#), or a .vcxproj file (C++). diff --git a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs index 13859a8c0eb..aff44a62540 100644 --- a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A file that can be the target in an invocation of `msbuild` or `dotnet build`. diff --git a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs similarity index 85% rename from csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs index e3da7ca22e9..2eecfca8f52 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild")] +[assembly: AssemblyTitle("Semmle.Autobuild.Shared")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Semmle")] -[assembly: AssemblyProduct("Semmle Visual Studio Autobuild")] -[assembly: AssemblyCopyright("Copyright © Semmle 2017")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj new file mode 100644 index 00000000000..66a5b26098c --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.0 + Semmle.Autobuild.Shared + Semmle.Autobuild.Shared + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + + + + + + + + diff --git a/csharp/autobuilder/Semmle.Autobuild/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/Solution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 0429b9f420c..e6563b31ff6 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -3,11 +3,10 @@ using Microsoft.Build.Exceptions; using System; using System.Collections.Generic; using System.Linq; -using Semmle.Util; using System.IO; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A solution file, extension .sln. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index 6962e8381d9..dca2a2b96bb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -18,7 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.FIELD_ACCESS; case SymbolKind.Property: - return ExprKind.PROPERTY_ACCESS; + return symbol is IPropertySymbol prop && prop.IsIndexer ? + ExprKind.INDEXER_ACCESS : ExprKind.PROPERTY_ACCESS; case SymbolKind.Event: return ExprKind.EVENT_ACCESS; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 502ef3250f7..daf37b57a63 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -69,19 +69,36 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (assignment != null) { - var assignmentEntity = new Expression(new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN)); - - CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0)); + var assignmentInfo = new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); + var assignmentEntity = new Expression(assignmentInfo); + var typeInfoRight = cx.GetTypeInfo(assignment.Right); + if (typeInfoRight.Type is null) + // The type may be null for nested initializers such as + // ```csharp + // new ClassWithArrayField() { As = { [0] = a } } + // ``` + // In this case we take the type from the assignment + // `As = { [0] = a }` instead + typeInfoRight = assignmentInfo.TypeInfo; + CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0, typeInfoRight)); var target = cx.GetSymbolInfo(assignment.Left); - if (target.Symbol == null) - { - cx.ModelError(assignment, "Unknown object initializer"); - new Unknown(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1)); - } - else - { + + // If the target is null, then assume that this is an array initializer (of the form `[...] = ...`) + + Expression access = target.Symbol is null ? + new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol)); + + if (assignment.Left is ImplicitElementAccessSyntax iea) + { + // An array/indexer initializer of the form `[...] = ...` + + int indexChild = 0; + foreach (var arg in iea.ArgumentList.Arguments) + { + Expression.Create(cx, arg.Expression, access, indexChild++); + } } } else diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 999903a1da8..982d21b2569 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -340,7 +340,6 @@ namespace Semmle.Extraction.CSharp.Entities if (isFullyConstructed) { - trapFile.is_constructed(this); trapFile.constructed_generic(this, Method.Create(Context, ConstructedFromSymbol)); foreach (var tp in symbol.GetAnnotatedTypeArguments()) { @@ -354,7 +353,6 @@ namespace Semmle.Extraction.CSharp.Entities } else { - trapFile.is_generic(this); foreach (var typeParam in symbol.TypeParameters.Select(tp => TypeParameter.Create(Context, tp))) { trapFile.type_parameters(typeParam, child, this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index a33d27b8f13..9a64115f24b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -202,7 +202,7 @@ namespace Semmle.Extraction.CSharp.Entities return obj != null && obj.GetType() == typeof(VarargsType); } - public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, null); + public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null); class VarargsTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index cecec5bc028..93c13726750 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -40,8 +40,6 @@ namespace Semmle.Extraction.CSharp.Entities } else if (symbol.IsReallyUnbound()) { - trapFile.is_generic(this); - for (int i = 0; i < symbol.TypeParameters.Length; ++i) { TypeParameter.Create(Context, symbol.TypeParameters[i]); @@ -52,7 +50,6 @@ namespace Semmle.Extraction.CSharp.Entities } else { - trapFile.is_constructed(this); trapFile.constructed_generic(this, Type.Create(Context, symbol.ConstructedFrom).TypeRef); for (int i = 0; i < symbol.TypeArguments.Length; ++i) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs index af5e154cb7f..7ef079b932e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities return obj != null && obj.GetType() == typeof(NullType); } - public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, null), NullableAnnotation.None); + public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None); class NullTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 4b24833337c..4123cc1808d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -306,16 +306,6 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("indexers", propKey, name, declaringType, memberType, unboundProperty); } - internal static void is_constructed(this TextWriter trapFile, IEntity typeOrMethod) - { - trapFile.WriteTuple("is_constructed", typeOrMethod); - } - - internal static void is_generic(this TextWriter trapFile, IEntity typeOrMethod) - { - trapFile.WriteTuple("is_generic", typeOrMethod); - } - internal static void local_function_stmts(this TextWriter trapFile, Entities.Statements.LocalFunction fnStmt, LocalFunction fn) { trapFile.WriteTuple("local_function_stmts", fnStmt, fn); diff --git a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs index 4462f112eb1..2067f869471 100644 --- a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs +++ b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs @@ -26,10 +26,9 @@ namespace Semmle.Extraction.CommentProcessing private readonly Dictionary duplicationGuardKeys = new Dictionary(); - private Key GetDuplicationGuardKey(Label label) + private Key? GetDuplicationGuardKey(Label label) { - Key duplicationGuardKey; - if (duplicationGuardKeys.TryGetValue(label, out duplicationGuardKey)) + if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey)) return duplicationGuardKey; return null; } @@ -60,7 +59,7 @@ namespace Semmle.Extraction.CommentProcessing /// The label of the element in the trap file. /// The duplication guard key of the element, if any. /// The location of the element. - public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc) + public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location loc) { if (loc != null && loc.IsInSource) elements[loc] = elementLabel; @@ -257,19 +256,24 @@ namespace Semmle.Extraction.CommentProcessing CommentBindingCallback cb ) { - CommentBlock block = new CommentBlock(); + CommentBlock? block = null; // Iterate comments until the commentEnumerator has gone past nextElement while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0) { + if(block is null) + block = new CommentBlock(commentEnumerator.Current.Value); + if (!block.CombinesWith(commentEnumerator.Current.Value)) { // Start of a new block, so generate the bindings for the old block first. GenerateBindings(block, elementStack, nextElement, cb); - block = new CommentBlock(); + block = new CommentBlock(commentEnumerator.Current.Value); + } + else + { + block.AddCommentLine(commentEnumerator.Current.Value); } - - block.AddCommentLine(commentEnumerator.Current.Value); // Get the next comment. if (!commentEnumerator.MoveNext()) @@ -280,7 +284,9 @@ namespace Semmle.Extraction.CommentProcessing } } - GenerateBindings(block, elementStack, nextElement, cb); + if(!(block is null)) + GenerateBindings(block, elementStack, nextElement, cb); + return true; } @@ -332,12 +338,18 @@ namespace Semmle.Extraction.CommentProcessing class CommentBlock : ICommentBlock { - private readonly List lines = new List(); + private readonly List lines; public IEnumerable CommentLines => lines; public Location Location { get; private set; } + public CommentBlock(ICommentLine firstLine) + { + lines = new List { firstLine }; + Location = firstLine.Location; + } + /// /// Determine whether commentlines should be merged. /// diff --git a/csharp/extractor/Semmle.Extraction/Comments.cs b/csharp/extractor/Semmle.Extraction/Comments.cs index 08d2a3e6947..457d478ca4c 100644 --- a/csharp/extractor/Semmle.Extraction/Comments.cs +++ b/csharp/extractor/Semmle.Extraction/Comments.cs @@ -74,7 +74,7 @@ namespace Semmle.Extraction.CommentProcessing /// The duplication guard key of the element, if any /// The comment block associated with the element /// The relationship between the commentblock and the element - public delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding); + public delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding); /// /// Computes the binding information between comments and program elements. @@ -88,7 +88,7 @@ namespace Semmle.Extraction.CommentProcessing /// Label of the element. /// The duplication guard key of the element, if any. /// Location of the element. - void AddElement(Label elementLabel, Key duplicationGuardKey, Location location); + void AddElement(Label elementLabel, Key? duplicationGuardKey, Location location); /// /// Registers a line of comment. diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 918642f198d..3e55c1068e2 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -34,7 +34,7 @@ namespace Semmle.Extraction return cachedModel; } - private SemanticModel cachedModel; + private SemanticModel? cachedModel; /// /// Access to the trap file. @@ -49,7 +49,31 @@ namespace Semmle.Extraction /// The entity factory. /// The initializer for the entity. /// The new/existing entity. - public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity where Type:struct + { + return CreateNonNullEntity(factory, init); + } + + /// + /// Creates a new entity using the factory. + /// + /// The entity factory. + /// The initializer for the entity. + /// The new/existing entity. + public Entity CreateNullableEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + { + return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); + } + + /// + /// Creates a new entity using the factory. + /// + /// The entity factory. + /// The initializer for the entity. + /// The new/existing entity. + public Entity CreateEntityFromSymbol(ICachedEntityFactory factory, Type init) + where Entity : ICachedEntity + where Type: ISymbol { return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); } @@ -135,8 +159,11 @@ namespace Semmle.Extraction public Label GetNewLabel() => new Label(GetNewId()); - private Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + public Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) + where Entity : ICachedEntity { + if (init is null) throw new ArgumentException("Unexpected null value", nameof(init)); + if (objectEntityCache.TryGetValue(init, out var cached)) return (Entity)cached; @@ -360,7 +387,7 @@ namespace Semmle.Extraction /// Symbol for reporting errors. /// The entity to populate. /// Thrown on invalid trap stack behaviour. - public void Populate(ISymbol optionalSymbol, ICachedEntity entity) + public void Populate(ISymbol? optionalSymbol, ICachedEntity entity) { if (WritingLabel) { @@ -453,9 +480,9 @@ namespace Semmle.Extraction /// The error message. /// A textual representation of the failed entity. /// The location of the error. - /// An optional stack trace of the error, or an empty string. + /// An optional stack trace of the error, or null. /// The severity of the error. - public void ExtractionError(string message, string entityText, Entities.Location location, string stackTrace = "", Severity severity = Severity.Error) + public void ExtractionError(string message, string entityText, Entities.Location location, string? stackTrace = null, Severity severity = Severity.Error) { var msg = new Message(message, entityText, location, stackTrace, severity); ExtractionError(msg); @@ -467,7 +494,7 @@ namespace Semmle.Extraction /// The text of the message. /// The symbol of the error, or null. /// The entity of the error, or null. - public void ExtractionError(string message, ISymbol optionalSymbol, IEntity optionalEntity) + public void ExtractionError(string message, ISymbol? optionalSymbol, IEntity optionalEntity) { if (!(optionalSymbol is null)) { @@ -539,7 +566,7 @@ namespace Semmle.Extraction /// Optional syntax node for error reporting. /// Optional symbol for error reporting. /// The action to perform. - static public void Try(this Context context, SyntaxNode node, ISymbol symbol, Action a) + static public void Try(this Context context, SyntaxNode? node, ISymbol? symbol, Action a) { try { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs index 45920a01d32..f2da5160636 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities readonly string assemblyPath; readonly IAssemblySymbol assembly; - Assembly(Context cx, Microsoft.CodeAnalysis.Location init) + Assembly(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { if (init == null) @@ -19,7 +19,7 @@ namespace Semmle.Extraction.Entities } else { - assembly = symbol.MetadataModule.ContainingAssembly; + assembly = init.MetadataModule.ContainingAssembly; var identity = assembly.Identity; var idString = identity.Name + " " + identity.Version; assemblyPath = cx.Extractor.GetAssemblyFile(idString); @@ -30,7 +30,7 @@ namespace Semmle.Extraction.Entities { if (assemblyPath != null) { - trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString(), + trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString() ?? "", assembly.Identity.Name, assembly.Identity.Version.ToString()); } } @@ -41,7 +41,7 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => symbol == null ? 91187354 : symbol.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as Assembly; if (other == null || other.GetType() != typeof(Assembly)) @@ -50,20 +50,20 @@ namespace Semmle.Extraction.Entities return Equals(symbol, other.symbol); } - public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc); + public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, loc); - class AssemblyConstructorFactory : ICachedEntityFactory + class AssemblyConstructorFactory : ICachedEntityFactory { public static readonly AssemblyConstructorFactory Instance = new AssemblyConstructorFactory(); - public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init); + public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init); } public static Location CreateOutputAssembly(Context cx) { if (cx.Extractor.OutputPath == null) throw new InternalError("Attempting to create the output assembly in standalone extraction mode"); - return AssemblyConstructorFactory.Instance.CreateEntity(cx, null); + return AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, null); } public override void WriteId(System.IO.TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs index 225482b2999..91dcab1adb8 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.Entities protected override void Populate(TextWriter trapFile) { - trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location, msg.StackTrace); + trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs index f52512a18da..cbdf1535fbb 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs @@ -50,12 +50,12 @@ namespace Semmle.Extraction.Entities Where(t => t.FilePath == Path). Select(tree => tree.GetText())) { - var rawText = text.ToString(); + var rawText = text.ToString() ?? ""; var lineCounts = LineCounter.ComputeLineCounts(rawText); if (rawText.Length > 0 && rawText[rawText.Length - 1] != '\n') lineCounts.Total++; trapFile.numlines(this, lineCounts); - Context.TrapWriter.Archive(fi.FullName, text.Encoding); + Context.TrapWriter.Archive(fi.FullName, text.Encoding ?? System.Text.Encoding.Default); } } @@ -111,17 +111,17 @@ namespace Semmle.Extraction.Entities } public static GeneratedFile Create(Context cx) => - GeneratedFileFactory.Instance.CreateEntity(cx, null); + GeneratedFileFactory.Instance.CreateNullableEntity(cx, null); - class GeneratedFileFactory : ICachedEntityFactory + class GeneratedFileFactory : ICachedEntityFactory { public static readonly GeneratedFileFactory Instance = new GeneratedFileFactory(); - public GeneratedFile Create(Context cx, string init) => new GeneratedFile(cx); + public GeneratedFile Create(Context cx, string? init) => new GeneratedFile(cx); } } - public override Microsoft.CodeAnalysis.Location ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; class FileFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs index 22b2144aceb..3c29ee38bd9 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs @@ -45,7 +45,7 @@ namespace Semmle.Extraction.Entities public static Folder Create(Context cx, DirectoryInfo folder) => FolderFactory.Instance.CreateEntity2(cx, folder); - public override Microsoft.CodeAnalysis.Location ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; class FolderFactory : ICachedEntityFactory { @@ -58,7 +58,7 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => Path.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Folder folder && folder.Path == Path; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs index 8e47a6d7ed1..926fa722ae6 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs @@ -26,15 +26,15 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => 98732567; - public override bool Equals(object obj) => obj != null && obj.GetType() == typeof(GeneratedLocation); + public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation); - public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, null); + public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateNullableEntity(cx, null); - class GeneratedLocationFactory : ICachedEntityFactory + class GeneratedLocationFactory : ICachedEntityFactory { public static GeneratedLocationFactory Instance = new GeneratedLocationFactory(); - public GeneratedLocation Create(Context cx, string init) => new GeneratedLocation(cx); + public GeneratedLocation Create(Context cx, string? init) => new GeneratedLocation(cx); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Location.cs b/csharp/extractor/Semmle.Extraction/Entities/Location.cs index a072fcaade6..d499e68c64f 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Location.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Location.cs @@ -1,17 +1,17 @@ namespace Semmle.Extraction.Entities { - public abstract class Location : CachedEntity + public abstract class Location : CachedEntity { - public Location(Context cx, Microsoft.CodeAnalysis.Location init) + public Location(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { } - public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => + public static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => (loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None) ? GeneratedLocation.Create(cx) - : loc.IsInSource ? SourceLocation.Create(cx, loc) + : loc.IsInSource ? NonGeneratedSourceLocation.Create(cx, loc) : Assembly.Create(cx, loc); - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => symbol; public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } @@ -24,7 +24,7 @@ namespace Semmle.Extraction.Entities /// The extraction context. /// The CodeAnalysis location. /// The Location entity. - public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location location) => + public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location? location) => Location.Create(cx, location); } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index 218a2a9d4ba..0c62a481539 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -1,58 +1,64 @@ +using System; using System.IO; using Microsoft.CodeAnalysis; namespace Semmle.Extraction.Entities { - public class SourceLocation : Location - { - protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location init) - : base(cx, init) { } + public abstract class SourceLocation : Location { + protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) + { + } - public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc); + public override bool NeedsPopulation => true; + } + + public class NonGeneratedSourceLocation : SourceLocation + { + protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) + : base(cx, init) + { + if (init is null) throw new ArgumentException("Location may not be null", nameof(init)); + Position = init.GetLineSpan(); + FileEntity = File.Create(Context, Position.Path); + } + + public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => SourceLocationFactory.Instance.CreateNullableEntity(cx, loc); public override void Populate(TextWriter trapFile) { - Position = symbol.GetLineSpan(); - FileEntity = File.Create(Context, Position.Path); trapFile.locations_default(this, FileEntity, Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, Position.Span.End.Line + 1, Position.Span.End.Character); } - public override bool NeedsPopulation => true; - public FileLinePositionSpan Position { get; - private set; } public File FileEntity { get; - private set; } public override void WriteId(System.IO.TextWriter trapFile) { - FileLinePositionSpan l = symbol.GetLineSpan(); - FileEntity = Entities.File.Create(Context, l.Path); trapFile.Write("loc,"); trapFile.WriteSubId(FileEntity); trapFile.Write(','); - trapFile.Write(l.Span.Start.Line + 1); + trapFile.Write(Position.Span.Start.Line + 1); trapFile.Write(','); - trapFile.Write(l.Span.Start.Character + 1); + trapFile.Write(Position.Span.Start.Character + 1); trapFile.Write(','); - trapFile.Write(l.Span.End.Line + 1); + trapFile.Write(Position.Span.End.Line + 1); trapFile.Write(','); - trapFile.Write(l.Span.End.Character); + trapFile.Write(Position.Span.End.Character); } - class SourceLocationFactory : ICachedEntityFactory + class SourceLocationFactory : ICachedEntityFactory { public static readonly SourceLocationFactory Instance = new SourceLocationFactory(); - public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new SourceLocation(cx, init); + public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new NonGeneratedSourceLocation(cx, init); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entity.cs b/csharp/extractor/Semmle.Extraction/Entity.cs index 0d499ffb765..616929dd47c 100644 --- a/csharp/extractor/Semmle.Extraction/Entity.cs +++ b/csharp/extractor/Semmle.Extraction/Entity.cs @@ -42,7 +42,7 @@ namespace Semmle.Extraction /// /// The location for reporting purposes. /// - Location ReportingLocation { get; } + Location? ReportingLocation { get; } /// /// How the entity handles .push and .pop. @@ -92,7 +92,7 @@ namespace Semmle.Extraction bool NeedsPopulation { get; } - object UnderlyingObject { get; } + object? UnderlyingObject { get; } } /// @@ -127,8 +127,11 @@ namespace Semmle.Extraction /// The factory used to construct the entity. /// The initializer for the entity, which may not be null. /// The entity. - public static Entity CreateEntity(this ICachedEntityFactory factory, Context cx, Type init) - where Entity : ICachedEntity => cx.CreateEntity(factory, init); + public static Entity CreateEntity(this ICachedEntityFactory factory, Context cx, Type init) where Type : notnull + where Entity : ICachedEntity => cx.CreateNonNullEntity(factory, init); + + public static Entity CreateNullableEntity(this ICachedEntityFactory factory, Context cx, Type init) + where Entity : ICachedEntity => cx.CreateNullableEntity(factory, init); /// /// Creates and populates a new entity, but uses a different cache. @@ -153,7 +156,7 @@ namespace Semmle.Extraction catch(Exception ex) // lgtm[cs/catch-of-all-exceptions] { trapFile.WriteLine("\""); - extractor.Message(new Message("Unhandled exception generating id", entity.ToString(), null, ex.StackTrace.ToString())); + extractor.Message(new Message("Unhandled exception generating id", entity.ToString() ?? "", null, ex.StackTrace)); } trapFile.WriteLine(); } diff --git a/csharp/extractor/Semmle.Extraction/FreshEntity.cs b/csharp/extractor/Semmle.Extraction/FreshEntity.cs index 6a9ae4684e7..d117eefc594 100644 --- a/csharp/extractor/Semmle.Extraction/FreshEntity.cs +++ b/csharp/extractor/Semmle.Extraction/FreshEntity.cs @@ -56,7 +56,7 @@ namespace Semmle.Extraction public override string ToString() => Label.ToString(); - public virtual Microsoft.CodeAnalysis.Location ReportingLocation => null; + public virtual Microsoft.CodeAnalysis.Location? ReportingLocation => null; public abstract TrapStackBehaviour TrapStackBehaviour { get; } } diff --git a/csharp/extractor/Semmle.Extraction/Id.cs b/csharp/extractor/Semmle.Extraction/Id.cs index ce4bc011859..e2a65e5206a 100644 --- a/csharp/extractor/Semmle.Extraction/Id.cs +++ b/csharp/extractor/Semmle.Extraction/Id.cs @@ -34,7 +34,7 @@ namespace Semmle.Extraction public override string ToString() => "*"; - public override bool Equals(object obj) => obj.GetType() == GetType(); + public override bool Equals(object? obj) => obj?.GetType() == GetType(); public override int GetHashCode() => 0; @@ -87,9 +87,9 @@ namespace Semmle.Extraction return TrapBuilder.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - if (obj.GetType() != GetType()) + if (obj is null || obj.GetType() != GetType()) return false; var id = (Key)obj; return TrapBuilder.ToString() == id.TrapBuilder.ToString(); @@ -133,8 +133,9 @@ namespace Semmle.Extraction public static bool operator !=(Label l1, Label l2) => l1.Value != l2.Value; - public override bool Equals(object other) + public override bool Equals(object? other) { + if (other is null) return false; return GetType() == other.GetType() && ((Label)other).Value == Value; } diff --git a/csharp/extractor/Semmle.Extraction/InternalError.cs b/csharp/extractor/Semmle.Extraction/InternalError.cs index 04b100a0ff5..a90685e068f 100644 --- a/csharp/extractor/Semmle.Extraction/InternalError.cs +++ b/csharp/extractor/Semmle.Extraction/InternalError.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction public InternalError(ISymbol symbol, string msg) { Text = msg; - EntityText = symbol.ToString(); + EntityText = symbol.ToString() ?? ""; Location = symbol.Locations.FirstOrDefault(); } @@ -30,7 +30,7 @@ namespace Semmle.Extraction Location = null; } - public Location Location { get; } + public Location? Location { get; } public string Text { get; } public string EntityText { get; } diff --git a/csharp/extractor/Semmle.Extraction/Layout.cs b/csharp/extractor/Semmle.Extraction/Layout.cs index d59e455083d..9ab7ed5738a 100644 --- a/csharp/extractor/Semmle.Extraction/Layout.cs +++ b/csharp/extractor/Semmle.Extraction/Layout.cs @@ -26,7 +26,7 @@ namespace Semmle.Extraction /// /// List of blocks in the layout file. /// - List blocks; + readonly List blocks; /// /// A subproject in the layout file. @@ -36,14 +36,14 @@ namespace Semmle.Extraction /// /// The trap folder, or null for current directory. /// - public readonly string TRAP_FOLDER; + public readonly string? TRAP_FOLDER; /// /// The source archive, or null to skip. /// - public readonly string SOURCE_ARCHIVE; + public readonly string? SOURCE_ARCHIVE; - public SubProject(string traps, string archive) + public SubProject(string? traps, string? archive) { TRAP_FOLDER = traps; SOURCE_ARCHIVE = archive; @@ -73,7 +73,7 @@ namespace Semmle.Extraction /// /// The file to look up. /// The relevant subproject, or null if not found. - public SubProject LookupProjectOrNull(string sourceFile) + public SubProject? LookupProjectOrNull(string sourceFile) { if (!useLayoutFile) return DefaultProject; @@ -113,13 +113,14 @@ namespace Semmle.Extraction /// Directory for source archive, or null for layout/no archive. /// Path of layout file, or null for no layout. /// Failed to read layout file. - public Layout(string traps, string archive, string layout) + public Layout(string? traps, string? archive, string? layout) { useLayoutFile = string.IsNullOrEmpty(traps) && !string.IsNullOrEmpty(layout); + blocks = new List(); if (useLayoutFile) { - ReadLayoutFile(layout); + ReadLayoutFile(layout!); DefaultProject = blocks[0].Directories; } else @@ -141,15 +142,12 @@ namespace Semmle.Extraction { var lines = File.ReadAllLines(layout); - blocks = new List(); - int i = 0; while (!lines[i].StartsWith("#")) i++; while (i < lines.Length) { - LayoutBlock block = new LayoutBlock(); - i = block.Read(lines, i); + LayoutBlock block = new LayoutBlock(lines, ref i); blocks.Add(block); } @@ -197,9 +195,9 @@ namespace Semmle.Extraction private readonly List conditions = new List(); - public Layout.SubProject Directories; + public readonly Layout.SubProject Directories; - string ReadVariable(string name, string line) + string? ReadVariable(string name, string line) { string prefix = name + "="; if (!line.StartsWith(prefix)) @@ -207,23 +205,22 @@ namespace Semmle.Extraction return line.Substring(prefix.Length).Trim(); } - public int Read(string[] lines, int start) + public LayoutBlock(string[] lines, ref int i) { // first line: #name - int i = start + 1; - var TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]); + i++; + string? TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]); // Don't care about ODASA_DB. ReadVariable("ODASA_DB", lines[i++]); - var SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]); + string? SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]); - Directories = new Extraction.Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE); + Directories = new Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE); // Don't care about ODASA_BUILD_ERROR_DIR. ReadVariable("ODASA_BUILD_ERROR_DIR", lines[i++]); while (i < lines.Length && !lines[i].StartsWith("#")) { conditions.Add(new Condition(lines[i++])); } - return i; } public bool Matches(string path) diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index ee274cde765..c617efaa5ba 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -15,23 +15,23 @@ namespace Semmle.Extraction public readonly string Text; public readonly string StackTrace; public readonly string EntityText; - public readonly Entities.Location Location; + public readonly Entities.Location? Location; - public Message(string text, string entityText, Entities.Location location, string stackTrace="", Severity severity = Severity.Error) + public Message(string text, string entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) { Severity = severity; Text = text; - StackTrace = stackTrace; + StackTrace = stackTrace ?? ""; EntityText = entityText; Location = location; } - public static Message Create(Context cx, string text, ISymbol symbol, string stackTrace= "", Severity severity = Severity.Error) + public static Message Create(Context cx, string text, ISymbol symbol, string? stackTrace = null, Severity severity = Severity.Error) { - return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); + return new Message(text, symbol.ToString() ?? "", Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); } - public static Message Create(Context cx, string text, SyntaxNode node, string stackTrace = "", Severity severity = Severity.Error) + public static Message Create(Context cx, string text, SyntaxNode node, string? stackTrace = null, Severity severity = Severity.Error) { return new Message(text, node.ToString(), Entities.Location.Create(cx, node.GetLocation()), stackTrace, severity); } diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index 48e2a00c9f3..b8a6d8be614 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -7,6 +7,7 @@ false Semmle.Extraction.ruleset win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction/Symbol.cs b/csharp/extractor/Semmle.Extraction/Symbol.cs index 57bb1ed11ad..925fba2e3fd 100644 --- a/csharp/extractor/Semmle.Extraction/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction/Symbol.cs @@ -16,7 +16,7 @@ namespace Semmle.Extraction public Label Label { get; set; } - public abstract Microsoft.CodeAnalysis.Location ReportingLocation { get; } + public abstract Microsoft.CodeAnalysis.Location? ReportingLocation { get; } public override string ToString() => Label.ToString(); @@ -39,15 +39,15 @@ namespace Semmle.Extraction public Context Context { - get; private set; + get; } public Initializer symbol { - get; private set; + get; } - object ICachedEntity.UnderlyingObject => symbol; + object? ICachedEntity.UnderlyingObject => symbol; public Initializer UnderlyingObject => symbol; @@ -75,9 +75,9 @@ namespace Semmle.Extraction Context.WithDuplicationGuard(key, a); } - public override int GetHashCode() => symbol.GetHashCode(); + public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as CachedEntity; return other?.GetType() == GetType() && Equals(other.symbol, symbol); diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction/TrapWriter.cs index 63b50744d7e..7ea08eafc1c 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction/TrapWriter.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction /// /// The location of the src_archive directory. /// - private readonly string archive; + private readonly string? archive; private static readonly Encoding UTF8 = new UTF8Encoding(false); private readonly bool discardDuplicates; @@ -45,7 +45,7 @@ namespace Semmle.Extraction readonly CompressionMode TrapCompression; - public TrapWriter(ILogger logger, string outputfile, string trap, string archive, bool discardDuplicates, CompressionMode trapCompression) + public TrapWriter(ILogger logger, string outputfile, string? trap, string? archive, bool discardDuplicates, CompressionMode trapCompression) { Logger = logger; TrapCompression = trapCompression; @@ -101,7 +101,7 @@ namespace Semmle.Extraction /// The output filename of the trap. /// public readonly string TrapFile; - string tmpFile; // The temporary file which is moved to trapFile once written. + string tmpFile = ""; // The temporary file which is moved to trapFile once written. /// /// Adds the specified input file to the source archive. It may end up in either the normal or long path area @@ -236,7 +236,7 @@ namespace Semmle.Extraction } } - public static string NestPaths(ILogger logger, string outerpath, string innerpath, InnerPathComputation innerPathComputation) + public static string NestPaths(ILogger logger, string? outerpath, string innerpath, InnerPathComputation innerPathComputation) { string nested = innerpath; if (!string.IsNullOrEmpty(outerpath)) @@ -276,7 +276,7 @@ namespace Semmle.Extraction } } - public static string TrapPath(ILogger logger, string folder, string filename, TrapWriter.CompressionMode trapCompression) + public static string TrapPath(ILogger logger, string? folder, string filename, TrapWriter.CompressionMode trapCompression) { filename = $"{Path.GetFullPath(filename)}.trap{TrapExtension(trapCompression)}"; if (string.IsNullOrEmpty(folder)) diff --git a/csharp/ql/src/API Abuse/FormatInvalid.ql b/csharp/ql/src/API Abuse/FormatInvalid.ql index f12dd08b74f..979af415936 100644 --- a/csharp/ql/src/API Abuse/FormatInvalid.ql +++ b/csharp/ql/src/API Abuse/FormatInvalid.ql @@ -1,7 +1,7 @@ /** * @name Invalid format string * @description Using a format string with an incorrect format causes a 'System.FormatException'. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cs/invalid-format-string @@ -11,7 +11,8 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall s, InvalidFormatString src -where src = s.getAFormatSource() -select src, "Invalid format string used in $@ formatting call.", s, "this" +from FormatCall s, InvalidFormatString src, PathNode source, PathNode sink +where hasFlowPath(src, source, s, sink) +select src, source, sink, "Invalid format string used in $@ formatting call.", s, "this" diff --git a/csharp/ql/src/API Abuse/FormatMissingArgument.ql b/csharp/ql/src/API Abuse/FormatMissingArgument.ql index 3e121481d5b..58385d4a295 100644 --- a/csharp/ql/src/API Abuse/FormatMissingArgument.ql +++ b/csharp/ql/src/API Abuse/FormatMissingArgument.ql @@ -1,7 +1,7 @@ /** * @name Missing format argument * @description Supplying too few arguments to a format string causes a 'System.FormatException'. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cs/format-argument-missing @@ -11,11 +11,14 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall format, ValidFormatString src, int used, int supplied +from + FormatCall format, ValidFormatString src, int used, int supplied, PathNode source, PathNode sink where - src = format.getAFormatSource() and + hasFlowPath(src, source, format, sink) and used = src.getAnInsert() and supplied = format.getSuppliedArguments() and used >= supplied -select format, "Argument '{" + used + "}' has not been supplied to $@ format string.", src, "this" +select format, source, sink, "Argument '{" + used + "}' has not been supplied to $@ format string.", + src, "this" diff --git a/csharp/ql/src/API Abuse/FormatUnusedArgument.ql b/csharp/ql/src/API Abuse/FormatUnusedArgument.ql index aff671ee876..226330d7dbf 100644 --- a/csharp/ql/src/API Abuse/FormatUnusedArgument.ql +++ b/csharp/ql/src/API Abuse/FormatUnusedArgument.ql @@ -1,7 +1,7 @@ /** * @name Unused format argument * @description Supplying more arguments than are required for a format string may indicate an error in the format string. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id cs/format-argument-unused @@ -11,11 +11,12 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall format, int unused, ValidFormatString src +from FormatCall format, int unused, ValidFormatString src, PathNode source, PathNode sink where - src = format.getAFormatSource() and + hasFlowPath(src, source, format, sink) and unused = format.getAnUnusedArgument(src) and not src.getValue() = "" -select format, "The $@ ignores $@.", src, "format string", format.getSuppliedExpr(unused), - "this supplied value" +select format, source, sink, "The $@ ignores $@.", src, "format string", + format.getSuppliedExpr(unused), "this supplied value" diff --git a/csharp/ql/src/Concurrency/Concurrency.qll b/csharp/ql/src/Concurrency/Concurrency.qll index d37b10e0301..aacd8308306 100644 --- a/csharp/ql/src/Concurrency/Concurrency.qll +++ b/csharp/ql/src/Concurrency/Concurrency.qll @@ -1,7 +1,8 @@ -// Various utilities for writing concurrency queries. +/** Classes for concurrency queries. */ + import csharp -class WaitCall extends MethodCall { +private class WaitCall extends MethodCall { WaitCall() { getTarget().hasName("Wait") and getTarget().getDeclaringType().hasQualifiedName("System.Threading.Monitor") @@ -10,22 +11,24 @@ class WaitCall extends MethodCall { Expr getExpr() { result = getArgument(0) } } +/** An expression statement containing a `Wait` call. */ class WaitStmt extends ExprStmt { WaitStmt() { getExpr() instanceof WaitCall } + /** Gets the expression that this wait call is waiting on. */ Expr getLock() { result = getExpr().(WaitCall).getExpr() } - // If we are waiting on a variable + /** Gets the variable that this wait call is waiting on, if any. */ Variable getWaitVariable() { result.getAnAccess() = getLock() } - // If we are waiting on 'this' + /** Holds if this wait call waits on `this`. */ predicate isWaitThis() { getLock() instanceof ThisAccess } - // If we are waiting on a typeof() + /** Gets the type that this wait call waits on, if any. */ Type getWaitTypeObject() { result = getLock().(TypeofExpr).getTypeAccess().getTarget() } } -class SynchronizedMethodAttribute extends Attribute { +private class SynchronizedMethodAttribute extends Attribute { SynchronizedMethodAttribute() { getType().hasQualifiedName("System.Runtime.CompilerServices.MethodImplAttribute") and exists(MemberConstantAccess a, MemberConstant mc | @@ -37,22 +40,29 @@ class SynchronizedMethodAttribute extends Attribute { } } -// A method with attribute [MethodImpl(MethodImplOptions.Synchronized)] -class SynchronizedMethod extends Method { +/** A method with attribute `[MethodImpl(MethodImplOptions.Synchronized)]`. */ +private class SynchronizedMethod extends Method { SynchronizedMethod() { getAnAttribute() instanceof SynchronizedMethodAttribute } + /** Holds if this method locks `this`. */ predicate isLockThis() { not isStatic() } + /** Gets the type that is locked by this method, if any. */ Type getLockTypeObject() { isStatic() and result = getDeclaringType() } } +/** A block that is locked by a `lock` statement. */ abstract class LockedBlock extends BlockStmt { + /** Holds if the `lock` statement locks `this`. */ abstract predicate isLockThis(); + /** Gets the lock variable of the `lock` statement, if any. */ abstract Variable getLockVariable(); + /** Gets the locked type of the `lock` statement, if any. */ abstract Type getLockTypeObject(); + /** Gets a statement in the scope of this locked block. */ Stmt getALockedStmt() { // Do this instead of getParent+, because we don't want to escape // delegates and lambdas @@ -62,7 +72,7 @@ abstract class LockedBlock extends BlockStmt { } } -class LockStmtBlock extends LockedBlock { +private class LockStmtBlock extends LockedBlock { LockStmtBlock() { exists(LockStmt s | this = s.getBlock()) } override predicate isLockThis() { exists(LockStmt s | this = s.getBlock() and s.isLockThis()) } @@ -76,9 +86,7 @@ class LockStmtBlock extends LockedBlock { } } -/** - * A call which may take a lock using one of the standard library classes. - */ +/** A call that may take a lock using one of the standard library methods. */ class LockingCall extends MethodCall { LockingCall() { this.getTarget() = @@ -91,7 +99,7 @@ class LockingCall extends MethodCall { } } -class SynchronizedMethodBlock extends LockedBlock { +private class SynchronizedMethodBlock extends LockedBlock { SynchronizedMethodBlock() { exists(SynchronizedMethod m | this = m.getStatementBody()) } override predicate isLockThis() { diff --git a/csharp/ql/src/Documentation/Documentation.qll b/csharp/ql/src/Documentation/Documentation.qll index ed69cf150ea..041a385e793 100644 --- a/csharp/ql/src/Documentation/Documentation.qll +++ b/csharp/ql/src/Documentation/Documentation.qll @@ -1,6 +1,8 @@ +/** Classes representing documentation comments. */ + import csharp -class SourceDeclaration extends Declaration { +private class SourceDeclaration extends Declaration { SourceDeclaration() { this.isSourceDeclaration() } } @@ -59,10 +61,13 @@ predicate isDocumentationNeeded(Modifiable decl) { class ReturnsXmlComment extends XmlComment { ReturnsXmlComment() { getOpenTag(_) = "returns" } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("returns", offset) } + /** Holds if the element in this comment is an opening tag at offset `offset`. */ predicate isOpenTag(int offset) { "returns" = getOpenTag(offset) } + /** Holds if the element in this comment is an empty tag at offset `offset`. */ predicate isEmptyTag(int offset) { "returns" = getEmptyTag(offset) } } @@ -70,8 +75,10 @@ class ReturnsXmlComment extends XmlComment { class ExceptionXmlComment extends XmlComment { ExceptionXmlComment() { getOpenTag(_) = "exception" } + /** Gets a `cref` attribute at offset `offset`, if any. */ string getCref(int offset) { result = getAttribute("exception", "cref", offset) } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("exception", offset) } } @@ -79,8 +86,10 @@ class ExceptionXmlComment extends XmlComment { class ParamXmlComment extends XmlComment { ParamXmlComment() { getOpenTag(_) = "param" } + /** Gets the name of this parameter at offset `offset`. */ string getName(int offset) { getAttribute("param", "name", offset) = result } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("param", offset) } } @@ -88,8 +97,10 @@ class ParamXmlComment extends XmlComment { class TypeparamXmlComment extends XmlComment { TypeparamXmlComment() { getOpenTag(_) = "typeparam" } + /** Gets the `name` attribute of this element at offset `offset`. */ string getName(int offset) { getAttribute("typeparam", "name", offset) = result } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("typeparam", offset) } } @@ -97,10 +108,13 @@ class TypeparamXmlComment extends XmlComment { class SummaryXmlComment extends XmlComment { SummaryXmlComment() { getOpenTag(_) = "summary" } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("summary", offset) } + /** Holds if the element in this comment has an open tag at offset `offset`. */ predicate isOpenTag(int offset) { "summary" = getOpenTag(offset) } + /** Holds if the element in this comment is empty at offset `offset`. */ predicate isEmptyTag(int offset) { "summary" = getEmptyTag(offset) } } diff --git a/csharp/ql/src/Language Abuse/ForeachCapture.ql b/csharp/ql/src/Language Abuse/ForeachCapture.ql index d4a97cdbc43..803081dcb73 100644 --- a/csharp/ql/src/Language Abuse/ForeachCapture.ql +++ b/csharp/ql/src/Language Abuse/ForeachCapture.ql @@ -75,15 +75,13 @@ Element getAssignmentTarget(Expr e) { Element getCollectionAssignmentTarget(Expr e) { // Store into collection via method exists( - MethodCall mc, Method m, IEnumerableFlow ief, CallableFlowSourceArg source, - CallableFlowSinkQualifier sink, int i + MethodCall mc, Method m, LibraryTypeDataFlow ltdf, CallableFlowSource source, + CallableFlowSink sink | - mc.getQualifier() = result.(Variable).getAnAccess() and - ief = mc.getQualifier().getType().getSourceDeclaration() and m = mc.getTarget().getSourceDeclaration() and - ief.callableFlow(source, sink, m, _) and - source.getArgumentIndex() = i and - e = mc.getArgument(i) + ltdf.callableFlow(source, AccessPath::empty(), sink, AccessPath::element(), m, _) and + e = source.getSource(mc) and + result.(Variable).getAnAccess() = sink.getSink(mc) ) or // Array initializer diff --git a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql index ebba14147ed..3c9b22583a8 100644 --- a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql +++ b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql @@ -14,14 +14,15 @@ import csharp import semmle.code.csharp.security.dataflow.flowsources.Stored import semmle.code.csharp.security.dataflow.XSS::XSS -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import semmle.code.csharp.dataflow.DataFlow2 +import DataFlow2::PathGraph class StoredTaintTrackingConfiguration extends TaintTrackingConfiguration { - override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } + override predicate isSource(DataFlow2::Node source) { source instanceof StoredFlowSource } } from - StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink, + StoredTaintTrackingConfiguration c, DataFlow2::PathNode source, DataFlow2::PathNode sink, string explanation where c.hasFlowPath(source, sink) and diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql index 533923ef9cd..abf3f0a55ad 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql @@ -16,11 +16,11 @@ import semmle.code.asp.WebConfig import semmle.code.csharp.frameworks.system.Web /** - * Holds if there exists a `Web.config` file in the snapshot that adds an `X-Frame-Options` header. + * Holds if the `Web.config` file `webConfig` adds an `X-Frame-Options` header. */ -predicate hasWebConfigXFrameOptions() { - // Looking for an entry in a Web.config file that looks like this: - // ``` +predicate hasWebConfigXFrameOptions(WebConfigXML webConfig) { + // Looking for an entry in `webConfig` that looks like this: + // ```xml // // // @@ -29,17 +29,13 @@ predicate hasWebConfigXFrameOptions() { // // // ``` - exists(XMLElement element | - element = - any(WebConfigXML webConfig) - .getARootElement() - .getAChild("system.webServer") - .getAChild("httpProtocol") - .getAChild("customHeaders") - .getAChild("add") - | - element.getAttributeValue("name") = "X-Frame-Options" - ) + webConfig + .getARootElement() + .getAChild("system.webServer") + .getAChild("httpProtocol") + .getAChild("customHeaders") + .getAChild("add") + .getAttributeValue("name") = "X-Frame-Options" } /** @@ -57,6 +53,6 @@ predicate hasCodeXFrameOptions() { from WebConfigXML webConfig where - not hasWebConfigXFrameOptions() and + not hasWebConfigXFrameOptions(webConfig) and not hasCodeXFrameOptions() select webConfig, "Configuration file is missing the X-Frame-Options setting." diff --git a/csharp/ql/src/Security Features/Encryption using ECB.qhelp b/csharp/ql/src/Security Features/Encryption using ECB.qhelp index 96bea263ff5..0315813d7bc 100644 --- a/csharp/ql/src/Security Features/Encryption using ECB.qhelp +++ b/csharp/ql/src/Security Features/Encryption using ECB.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> -

ECB should not be used as a mode for encryption. It has a dangerous weaknesses. Data is encrypted the same way every time -meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages very vulnerable +

ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time +meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable to replay attacks.

diff --git a/csharp/ql/src/Stubs/Stubs.qll b/csharp/ql/src/Stubs/Stubs.qll index 97ae6b4fd26..f8b704cba8b 100644 --- a/csharp/ql/src/Stubs/Stubs.qll +++ b/csharp/ql/src/Stubs/Stubs.qll @@ -5,7 +5,7 @@ * This will generate stubs for all the required dependencies as well. * * Use - * ``` + * ```ql * select generatedCode() * ``` * to retrieve the generated C# code. diff --git a/csharp/ql/src/cil.qll b/csharp/ql/src/cil.qll index 7252542414c..b46c328ab91 100644 --- a/csharp/ql/src/cil.qll +++ b/csharp/ql/src/cil.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling the Common Intermediate Language (CIL). + */ + import semmle.code.cil.CIL as CIL diff --git a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls index 3646204da7d..44fe11937e4 100644 --- a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls +++ b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-csharp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls index 83fe265b2aa..9c811406eeb 100644 --- a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls +++ b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-csharp - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references diff --git a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls new file mode 100644 index 00000000000..f5df6527965 --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls @@ -0,0 +1,6 @@ +- description: Security-and-quality queries for C# +- qlpack: codeql-csharp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-security-extended.qls b/csharp/ql/src/codeql-suites/csharp-security-extended.qls new file mode 100644 index 00000000000..f4efe70892c --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-extended.qls @@ -0,0 +1,6 @@ +- description: Security-extended queries for C# +- qlpack: codeql-csharp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml new file mode 100644 index 00000000000..53ad48be212 --- /dev/null +++ b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml @@ -0,0 +1,4 @@ +- description: C# queries which overlap with dependency analysis +- exclude: + query path: + - Security Features/CWE-937/VulnerablePackage.ql diff --git a/csharp/ql/src/csharp.qll b/csharp/ql/src/csharp.qll index a7f10c3f3c4..2a44f6e864a 100644 --- a/csharp/ql/src/csharp.qll +++ b/csharp/ql/src/csharp.qll @@ -35,11 +35,5 @@ import semmle.code.csharp.dataflow.DataFlow import semmle.code.csharp.dataflow.TaintTracking import semmle.code.csharp.dataflow.SSA -/** DEPRECATED: Use `ControlFlow` instead. */ -deprecated module ControlFlowGraph { - import semmle.code.csharp.controlflow.ControlFlowGraph - import ControlFlow -} - /** Whether the source was extracted without a build command. */ predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) } diff --git a/csharp/ql/src/definitions.ql b/csharp/ql/src/definitions.ql index be78cf99704..a2f893ef126 100644 --- a/csharp/ql/src/definitions.ql +++ b/csharp/ql/src/definitions.ql @@ -6,167 +6,8 @@ * @id cs/jump-to-definition */ -import csharp +import definitions -/** An element with an associated definition. */ -abstract class Use extends @type_mention_parent { - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - exists(Location l | - l = this.(Element).getLocation() or - l = this.(TypeMention).getLocation() - | - filepath = l.getFile().getAbsolutePath() and - startline = l.getStartLine() and - startcolumn = l.getStartColumn() and - endline = l.getEndLine() and - endcolumn = l.getEndColumn() - ) - } - - /** Gets the definition associated with this element. */ - abstract Declaration getDefinition(); - - /** - * Gets the type of use. - * - * - `"M"`: call. - * - `"V"`: variable use. - * - `"T"`: type reference. - */ - abstract string getUseType(); - - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** A method call/access. */ -class MethodUse extends Use, QualifiableExpr { - MethodUse() { - this instanceof MethodCall or - this instanceof MethodAccess - } - - /** Gets the qualifier of this method use, if any. */ - private Expr getFormatQualifier() { - ( - if this.getQualifiedDeclaration().(Method).isExtensionMethod() - then result = this.(MethodCall).getArgument(0) - else result = this.getQualifier() - ) and - not result.isImplicit() - } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - Use.super.hasLocationInfo(filepath, _, _, _, _) and - endline = startline and - endcolumn = startcolumn + this.getQualifiedDeclaration().getName().length() - 1 and - ( - exists(Location ql | ql = this.getFormatQualifier().getLocation() | - startline = ql.getEndLine() and - startcolumn = ql.getEndColumn() + 2 - ) - or - not exists(this.getFormatQualifier()) and - exists(Location l | l = this.getLocation() | - startline = l.getStartLine() and - startcolumn = l.getStartColumn() - ) - ) - } - - override Method getDefinition() { result = getQualifiedDeclaration().getSourceDeclaration() } - - override string getUseType() { result = "M" } - - override string toString() { result = this.(Expr).toString() } -} - -/** An access. */ -class AccessUse extends Access, Use { - AccessUse() { - not this.getTarget().(Parameter).getCallable() instanceof Accessor and - not this = any(LocalVariableDeclAndInitExpr d).getLValue() and - not this.isImplicit() and - not this instanceof MethodAccess and // handled by `MethodUse` - not this instanceof TypeAccess and // handled by `TypeMentionUse` - not this.(FieldAccess).getParent() instanceof Field and // Enum initializer - not this.(FieldAccess).getParent().getParent() instanceof Field and // Field initializer - not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer - } - - /** Gets the qualifier of this acccess, if any. */ - private Expr getFormatQualifier() { - result = this.(QualifiableExpr).getQualifier() and - not result.isImplicit() - } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - exists(Location ql | ql = this.getFormatQualifier().getLocation() | - startline = ql.getEndLine() and - startcolumn = ql.getEndColumn() + 2 and - Use.super.hasLocationInfo(filepath, _, _, endline, endcolumn) - ) - or - not exists(this.getFormatQualifier()) and - Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - override Declaration getDefinition() { result = this.getTarget().getSourceDeclaration() } - - override string getUseType() { - if this instanceof Call or this instanceof LocalFunctionAccess - then result = "M" - else - if this instanceof BaseAccess or this instanceof ThisAccess - then result = "T" - else result = "V" - } - - override string toString() { result = this.(Access).toString() } -} - -/** A type mention. */ -class TypeMentionUse extends Use, TypeMention { - TypeMentionUse() { - // In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want - // uses for the nested type mentions - forall(TypeMention child, Type t | - child.getParent() = this and - t = this.getType() - | - not t instanceof ArrayType and - not t instanceof NullableType and - not t instanceof PointerType and - not t instanceof TupleType - ) - } - - override Type getDefinition() { result = this.getType().getSourceDeclaration() } - - override string getUseType() { - if this.getTarget() instanceof ObjectCreation - then result = "M" // constructor call - else result = "T" - } - - override string toString() { result = TypeMention.super.toString() } -} - -from Use use, Declaration definition -where - definition = use.getDefinition() and - definition.fromSource() -select use, definition, use.getUseType() +from Use use, Declaration def, string kind +where def = definitionOf(use, kind) +select use, def, kind diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll new file mode 100644 index 00000000000..bc78f285af9 --- /dev/null +++ b/csharp/ql/src/definitions.qll @@ -0,0 +1,181 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import csharp + +/** An element with an associated definition. */ +abstract class Use extends @type_mention_parent { + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(Location l | + l = this.(Element).getLocation() or + l = this.(TypeMention).getLocation() + | + filepath = l.getFile().getAbsolutePath() and + startline = l.getStartLine() and + startcolumn = l.getStartColumn() and + endline = l.getEndLine() and + endcolumn = l.getEndColumn() + ) + } + + /** Gets the definition associated with this element. */ + abstract Declaration getDefinition(); + + /** + * Gets the type of use. + * + * - `"M"`: call. + * - `"V"`: variable use. + * - `"T"`: type reference. + */ + abstract string getUseType(); + + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** A method call/access. */ +private class MethodUse extends Use, QualifiableExpr { + MethodUse() { + this instanceof MethodCall or + this instanceof MethodAccess + } + + /** Gets the qualifier of this method use, if any. */ + private Expr getFormatQualifier() { + ( + if this.getQualifiedDeclaration().(Method).isExtensionMethod() + then result = this.(MethodCall).getArgument(0) + else result = this.getQualifier() + ) and + not result.isImplicit() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + Use.super.hasLocationInfo(filepath, _, _, _, _) and + endline = startline and + endcolumn = startcolumn + this.getQualifiedDeclaration().getName().length() - 1 and + ( + exists(Location ql | ql = this.getFormatQualifier().getLocation() | + startline = ql.getEndLine() and + startcolumn = ql.getEndColumn() + 2 + ) + or + not exists(this.getFormatQualifier()) and + exists(Location l | l = this.getLocation() | + startline = l.getStartLine() and + startcolumn = l.getStartColumn() + ) + ) + } + + override Method getDefinition() { result = getQualifiedDeclaration().getSourceDeclaration() } + + override string getUseType() { result = "M" } + + override string toString() { result = this.(Expr).toString() } +} + +/** An access. */ +private class AccessUse extends Access, Use { + AccessUse() { + not this.getTarget().(Parameter).getCallable() instanceof Accessor and + not this = any(LocalVariableDeclAndInitExpr d).getLValue() and + not this.isImplicit() and + not this instanceof MethodAccess and // handled by `MethodUse` + not this instanceof TypeAccess and // handled by `TypeMentionUse` + not this.(FieldAccess).getParent() instanceof Field and // Enum initializer + not this.(FieldAccess).getParent().getParent() instanceof Field and // Field initializer + not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer + } + + /** Gets the qualifier of this acccess, if any. */ + private Expr getFormatQualifier() { + result = this.(QualifiableExpr).getQualifier() and + not result.isImplicit() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(Location ql | ql = this.getFormatQualifier().getLocation() | + startline = ql.getEndLine() and + startcolumn = ql.getEndColumn() + 2 and + Use.super.hasLocationInfo(filepath, _, _, endline, endcolumn) + ) + or + not exists(this.getFormatQualifier()) and + Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + override Declaration getDefinition() { result = this.getTarget().getSourceDeclaration() } + + override string getUseType() { + if this instanceof Call or this instanceof LocalFunctionAccess + then result = "M" + else + if this instanceof BaseAccess or this instanceof ThisAccess + then result = "T" + else result = "V" + } + + override string toString() { result = this.(Access).toString() } +} + +/** A type mention. */ +private class TypeMentionUse extends Use, TypeMention { + TypeMentionUse() { + // In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want + // uses for the nested type mentions + forall(TypeMention child, Type t | + child.getParent() = this and + t = this.getType() + | + not t instanceof ArrayType and + not t instanceof NullableType and + not t instanceof PointerType and + not t instanceof TupleType + ) + } + + override Type getDefinition() { result = this.getType().getSourceDeclaration() } + + override string getUseType() { + if this.getTarget() instanceof ObjectCreation + then result = "M" // constructor call + else result = "T" + } + + override string toString() { result = TypeMention.super.toString() } +} + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + */ +cached +Declaration definitionOf(Use use, string kind) { + result = use.getDefinition() and + result.fromSource() and + kind = use.getUseType() +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/csharp/ql/src/dotnet.qll b/csharp/ql/src/dotnet.qll index 510f6967127..b583edda18a 100644 --- a/csharp/ql/src/dotnet.qll +++ b/csharp/ql/src/dotnet.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling .NET definitions for both C# and CIL code. + */ + import semmle.code.dotnet.DotNet as DotNet diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs new file mode 100644 index 00000000000..5913e7e1bbf --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using System.Web; +using System.Net; + +public class TaintedWebClientHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + String url = ctx.Request.QueryString["domain"]; + + // BAD: This could read any file on the filesystem. (../../../../etc/passwd) + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + + // BAD: This could still read any file on the filesystem. (https://../../../../etc/passwd) + if (url.StartsWith("https://")){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + + // GOOD: IsWellFormedUriString ensures that it is a valid URL + if (Uri.IsWellFormedUriString(url, UriKind.Absolute)){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + } +} diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp new file mode 100644 index 00000000000..77721307eda --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp @@ -0,0 +1,58 @@ + + + +

The WebClient class provides a variety of methods for data transmission and +communication with a particular URI. Despite of the class' naming convention, +the URI scheme can also identify local resources, not only remote ones. Tainted +by user-supplied input, the URI can be leveraged to access resources available +on the local file system, therefore leading to the disclosure of sensitive +information. This can be trivially achieved by supplying path traversal +sequences (../) followed by an existing directory or file path.

+ +

Sanitization of user-supplied URI values using the +StartsWith("https://") method is deemed insufficient in preventing +arbitrary file reads. This is due to the fact that .NET ignores the protocol +handler (https in this case) in URIs like the following: +"https://../../../../etc/passwd".

+ +
+ + +

Validate user input before using it to ensure that is a URI of an external +resource and not a local one. +Potential solutions:

+ +
    +
  • Sanitize potentially tainted paths using +System.Uri.IsWellFormedUriString.
  • +
+ +
+ + +

In the first example, a domain name is read from a HttpRequest +and then this domain is requested using the method DownloadString. +However, a malicious user could enter a local path - for example, +"../../../etc/passwd" instead of a domain. +In the second example, it appears that the user is restricted to the HTTPS +protocol handler. However, a malicious user could still enter a local path, +since as explained above the protocol handler will be ignored by .net. For +example, the string "https://../../../etc/passwd" will result in the code +reading the file located at "/etc/passwd", which is the system's password file. +This file would then be sent back to the user, giving them access to all the +system's passwords.

+ + + +
+ + +
  • +OWASP: +Path Traversal. +
  • + +
    +
    diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql new file mode 100644 index 00000000000..513c658cf92 --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql @@ -0,0 +1,23 @@ +/** + * @name Uncontrolled data used in a WebClient + * @description The WebClient class allows developers to request resources, + * accessing resources influenced by users can allow an attacker to access local files. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cs/webclient-path-injection + * @tags security + * external/cwe/cwe-099 + * external/cwe/cwe-023 + * external/cwe/cwe-036 + * external/cwe/cwe-073 + */ + +import csharp +import TaintedWebClientLib +import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph + +from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used in a method of WebClient.", + source.getNode(), "User-provided value" diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll new file mode 100644 index 00000000000..e9da88e0d27 --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll @@ -0,0 +1,82 @@ +import csharp +import semmle.code.csharp.frameworks.system.Net +import semmle.code.csharp.frameworks.System +import semmle.code.csharp.security.dataflow.flowsources.Remote +import semmle.code.csharp.security.Sanitizers + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system.Net +/** The `System.Net.WebClient` class. */ +class SystemNetWebClientClass extends SystemNetClass { + SystemNetWebClientClass() { this.hasName("WebClient") } + + /** Gets the `DownloadString` method. */ + Method getDownloadStringMethod() { result = this.getAMethod("DownloadString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.System +//Extend the already existent SystemUriClass to not touch the stdlib. +/** The `System.Uri` class. */ +class SystemUriClassExtra extends SystemUriClass { + /** Gets the `IsWellFormedUriString` method. */ + Method getIsWellFormedUriStringMethod() { result = this.getAMethod("IsWellFormedUriString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system +/** + * A data flow source for uncontrolled data in path expression vulnerabilities. + */ +abstract class Source extends DataFlow::Node { } + +/** + * A data flow sink for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sink extends DataFlow::ExprNode { } + +/** + * A sanitizer for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sanitizer extends DataFlow::ExprNode { } + +/** + * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities. + */ +class TaintTrackingConfiguration extends TaintTracking::Configuration { + TaintTrackingConfiguration() { this = "TaintedWebClientLib" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** A source of remote user input. */ +class RemoteSource extends Source { + RemoteSource() { this instanceof RemoteFlowSource } +} + +/** + * A path argument to a `WebClient` method call that has an address argument. + */ +class WebClientSink extends Sink { + WebClientSink() { + exists(Method m | m = any(SystemNetWebClientClass f).getAMethod() | + this.getExpr() = m.getACall().getArgumentForName("address") + ) + } +} + +/** + * A call to `System.Uri.IsWellFormedUriString` that is considered to sanitize the input. + */ +class RequestMapPathSanitizer extends Sanitizer { + RequestMapPathSanitizer() { + exists(Method m | m = any(SystemUriClassExtra uri).getIsWellFormedUriStringMethod() | + this.getExpr() = m.getACall().getArgument(0) + ) + } +} + +private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { } + +private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { } diff --git a/csharp/ql/src/semmle/code/csharp/ir/IR.qll b/csharp/ql/src/experimental/ir/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IR.qll rename to csharp/ql/src/experimental/ir/IR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/experimental/ir/IRConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/IRConfiguration.qll diff --git a/csharp/ql/src/experimental/ir/IRConsistency.ql b/csharp/ql/src/experimental/ir/IRConsistency.ql new file mode 100644 index 00000000000..375d38ec5de --- /dev/null +++ b/csharp/ql/src/experimental/ir/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id csharp/ir-consistency-check + */ + +import implementation.raw.IRConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/experimental/ir/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql rename to csharp/ql/src/experimental/ir/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll b/csharp/ql/src/experimental/ir/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll rename to csharp/ql/src/experimental/ir/PrintIR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/Util.qll b/csharp/ql/src/experimental/ir/Util.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/Util.qll rename to csharp/ql/src/experimental/ir/Util.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll b/csharp/ql/src/experimental/ir/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/ValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll similarity index 58% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll rename to csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 650c15f189a..32e36bb6787 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -17,6 +21,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,8 +33,6 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } -GotoEdge gotoEdge() { result = TGotoEdge() } - /** * A "true" edge, representing the successor of a conditional branch when the * condition is non-zero. @@ -38,8 +41,6 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } -TrueEdge trueEdge() { result = TTrueEdge() } - /** * A "false" edge, representing the successor of a conditional branch when the * condition is zero. @@ -48,8 +49,6 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } -FalseEdge falseEdge() { result = TFalseEdge() } - /** * An "exception" edge, representing the successor of an instruction when that * instruction's evaluation throws an exception. @@ -58,8 +57,6 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } -ExceptionEdge exceptionEdge() { result = TExceptionEdge() } - /** * A "default" edge, representing the successor of a `Switch` instruction when * none of the case values matches the condition value. @@ -68,8 +65,6 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } -DefaultEdge defaultEdge() { result = TDefaultEdge() } - /** * A "case" edge, representing the successor of a `Switch` instruction when the * the condition value matches a correponding `case` label. @@ -86,9 +81,59 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } -CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +/** + * Predicates to access the single instance of each `EdgeKind` class. + */ +module EdgeKind { + /** + * Gets the single instance of the `GotoEdge` class. + */ + GotoEdge gotoEdge() { result = TGotoEdge() } + + /** + * Gets the single instance of the `TrueEdge` class. + */ + TrueEdge trueEdge() { result = TTrueEdge() } + + /** + * Gets the single instance of the `FalseEdge` class. + */ + FalseEdge falseEdge() { result = TFalseEdge() } + + /** + * Gets the single instance of the `ExceptionEdge` class. + */ + ExceptionEdge exceptionEdge() { result = TExceptionEdge() } + + /** + * Gets the single instance of the `DefaultEdge` class. + */ + DefaultEdge defaultEdge() { result = TDefaultEdge() } + + /** + * Gets the `CaseEdge` representing a `case` label with the specified lower and upper bounds. + * For example: + * ``` + * switch (x) { + * case 1: // Edge kind is `caseEdge("1", "1")` + * return x; + * case 2...8: // Edge kind is `caseEdge("2", "8")` + * return x - 1; + * default: // Edge kind is `defaultEdge()` + * return 0; + * } + * ``` + */ + CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll similarity index 70% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll rename to csharp/ql/src/experimental/ir/implementation/IRType.qll index 9a75ca19154..3bf3bf2e276 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** @@ -111,6 +112,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -128,7 +131,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -137,13 +140,33 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. +} + +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -152,13 +175,15 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -167,6 +192,8 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** @@ -275,12 +302,24 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } -module IRTypeSanity { +/** + * INTERNAL: Do not use. + * Query predicates used to check invariants that should hold for all `IRType` objects. To run all + * consistency queries for the IR, including the ones below, run + * "semmle/code/cpp/IR/IRConsistency.ql". + */ +module IRTypeConsistency { + /** + * Holds if the type has no result for `IRType.getCanonicalLanguageType()`. + */ query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" } + /** + * Holds if the type has more than one result for `IRType.getCanonicalLanguageType()`. + */ query predicate multipleCanonicalLanguageTypes(IRType type, string message) { strictcount(type.getCanonicalLanguageType()) > 1 and message = @@ -288,11 +327,17 @@ module IRTypeSanity { concat(type.getCanonicalLanguageType().toString(), ", ") } + /** + * Holds if the type has no result for `LanguageType.getIRType()`. + */ query predicate missingIRType(Language::LanguageType type, string message) { not exists(type.getIRType()) and message = "`LanguageType` does not have a corresponding `IRType`." } + /** + * Holds if the type has more than one result for `LanguageType.getIRType()`. + */ query predicate multipleIRTypes(Language::LanguageType type, string message) { strictcount(type.getIRType()) > 1 and message = @@ -300,5 +345,5 @@ module IRTypeSanity { concat(type.getIRType().toString(), ", ") } - import Language::LanguageTypeSanity + import Language::LanguageTypeConsistency } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll rename to csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll index eac4d333afc..5e11a310e2f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** @@ -92,11 +99,3 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess { class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess { override string toString() { result = "chi(partial)" } } - -/** - * The operand accesses memory not modeled in SSA. Used only on the result of - * `UnmodeledDefinition` and on the operands of `UnmodeledUse`. - */ -class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess { - override string toString() { result = "unmodeled" } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll rename to csharp/ql/src/experimental/ir/implementation/Opcode.qll index e7a0b6f1b4f..c4134d240ab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -45,7 +50,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -60,8 +65,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -88,7 +91,11 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** @@ -141,10 +148,20 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -152,44 +169,127 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. + */ abstract class CopyOpcode extends Opcode { } +/** + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - +/** + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. + */ abstract class ReturnOpcode extends Opcode { } +/** + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. + */ abstract class ThrowOpcode extends Opcode { } +/** + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. + */ abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -325,7 +425,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -334,51 +436,111 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { + /** + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -387,14 +549,29 @@ module Opcode { } } + /** + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -403,154 +580,344 @@ module Opcode { } } + /** + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + /** + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. + */ + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } + /** + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -559,48 +926,67 @@ module Opcode { } } + /** + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } - class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { - final override string toString() { result = "UnmodeledDefinition" } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof UnmodeledMemoryAccess - } - } - - class UnmodeledUse extends Opcode, TUnmodeledUse { - final override string toString() { result = "UnmodeledUse" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof UnmodeledUseOperandTag - } - } - + /** + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -609,6 +995,11 @@ module Opcode { } } + /** + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -619,92 +1010,187 @@ module Opcode { } } + /** + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -719,6 +1205,11 @@ module Opcode { } } + /** + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -728,10 +1219,20 @@ module Opcode { } } + /** + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll new file mode 100644 index 00000000000..5f230de560d --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll @@ -0,0 +1,17 @@ +/** + * Defines the public interface to temporary variable tags, which describe the reason a particular + * `IRTempVariable` was generated. + */ + +private import internal.TempVariableTagInternal +private import Imports::TempVariableTag + +/** + * A reason that a particular IR temporary variable was generated. For example, it could be + * generated to hold the return value of a function, or to hold the result of a `?:` operator + * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. + */ +class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ + string toString() { result = getTempVariableTagId(this) } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll diff --git a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll new file mode 100644 index 00000000000..0fedd38bfbd --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll @@ -0,0 +1,19 @@ +/** + * Provides a stub implementation of the required aliased SSA interface until we implement aliased + * SSA construction for C#. + */ + +private import IRFunctionBase +private import TInstruction + +module SSA { + class MemoryLocation = boolean; + + predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) { + none() + } + + predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() } + + predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll new file mode 100644 index 00000000000..ebcc9573bce --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll new file mode 100644 index 00000000000..ebcc9573bce --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 00000000000..60895ce3d26 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,27 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ + +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 00000000000..f2da59bbb1d --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll new file mode 100644 index 00000000000..ebcc9573bce --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll new file mode 100644 index 00000000000..8bacf51d8a2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll rename to csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll index 227b1a34041..ac284440648 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll @@ -1,3 +1,8 @@ +/** + * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` + * plays in the evaluation of its `Instruction`. + */ + private import OperandTagInternal private newtype TOperandTag = @@ -10,7 +15,6 @@ private newtype TOperandTag = TLeftOperand() or TRightOperand() or TConditionOperand() or - TUnmodeledUseOperand() or TCallTargetOperand() or TThisArgumentOperand() or TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or @@ -24,10 +28,18 @@ private newtype TOperandTag = * an `Instruction` is determined by the instruction's opcode. */ abstract class OperandTag extends TOperandTag { + /** Gets a textual representation of this operand tag */ abstract string toString(); + /** + * Gets an integer that represents where this this operand will appear in the operand list of an + * instruction when the IR is printed. + */ abstract int getSortOrder(); + /** + * Gets a label that will appear before the operand when the IR is printed. + */ string getLabel() { result = "" } } @@ -47,7 +59,7 @@ abstract class RegisterOperandTag extends OperandTag { } abstract class TypedOperandTag extends MemoryOperandTag { } // Note: individual subtypes are listed in the order that the operands should -// appear in the operand list of the instruction when printing. +// appear in the operand list of the instruction when the IR is printed. /** * The address operand of an instruction that loads or stores a value from * memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`). @@ -152,18 +164,6 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { ConditionOperandTag conditionOperand() { result = TConditionOperand() } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand { - final override string toString() { result = "UnmodeledUse" } - - final override int getSortOrder() { result = 9 } -} - -UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() } - /** * The operand representing the target function of an `Call` instruction. */ @@ -221,7 +221,9 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { +abstract class ChiOperandTag extends MemoryOperandTag { } + +class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } final override int getSortOrder() { result = 13 } @@ -231,7 +233,7 @@ class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } -class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand { +class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override string toString() { result = "ChiPartial" } final override int getSortOrder() { result = 14 } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll new file mode 100644 index 00000000000..ebcc9573bce --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll new file mode 100644 index 00000000000..e2b2c408a4f --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll @@ -0,0 +1,7 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction +private import experimental.ir.implementation.TempVariableTag as TempVariableTag_ + +module Imports { + module TempVariableTag = TempVariableTag_; +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll new file mode 100644 index 00000000000..e16b71733b5 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,97 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +cached +newtype TInstruction = + TRawInstruction( + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 00000000000..6200f2a2796 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.Opcode as Opcode diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 00000000000..978d2c41aa7 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction +import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import AliasedSSAStub as AliasedSSA diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll new file mode 100644 index 00000000000..6d9f3e1e2db --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll @@ -0,0 +1,6 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.TempVariableTag as TempVariableTag_ + +module Imports { + module TempVariableTag = TempVariableTag_; +} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll new file mode 100644 index 00000000000..3fa0f1b78be --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -0,0 +1,75 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + +import IRFunction +import Instruction +import IRBlock +import IRVariable +import Operand +private import internal.IRImports as Imports +import Imports::EdgeKind +import Imports::IRType +import Imports::MemoryAccessKind + +private newtype TIRPropertyProvider = MkIRPropertyProvider() + +/** + * A class that provides additional properties to be dumped for IR instructions and blocks when using + * the PrintIR module. Libraries that compute additional facts about IR elements can extend the + * single instance of this class to specify the additional properties computed by the library. + */ +class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ + string toString() { result = "IRPropertyProvider" } + + /** + * Gets the value of the property named `key` for the specified instruction. + */ + string getInstructionProperty(Instruction instruction, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified block. + */ + string getBlockProperty(IRBlock block, string key) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll similarity index 71% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index dce1717bdc9..d827ed3cf82 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,49 +20,89 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -70,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -91,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -206,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql new file mode 100644 index 00000000000..a35d67a23ed --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Raw IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id csharp/raw-ir-consistency-check + */ + +import IRConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll new file mode 100644 index 00000000000..6a87b9b4b5f --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(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) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + 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, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * 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, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * 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, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + 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 + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll similarity index 61% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll index 1e9c2d1d913..5968e58f90b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ @@ -40,16 +28,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll similarity index 76% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index 0d5e7fe595c..146fc270738 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,10 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } +} + +/** + * A temporary variable generated to hold the `this` pointer. + */ +class IRThisVariable extends IRTempVariable, IRParameter { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -240,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -257,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -265,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 780f636ff10..0fd31dbd9c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -320,8 +343,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -393,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -408,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -475,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -497,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -506,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -542,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is true. + */ + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -635,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -779,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -858,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -868,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -878,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -888,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -898,16 +1466,33 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + /** Gets the successor instruction along the default edge of the switch, if any. */ + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -937,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -982,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -997,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1047,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1057,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1088,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1104,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1112,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1119,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1212,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1230,10 +1854,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ @@ -1248,12 +1868,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * @@ -1351,26 +1965,33 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1383,3 +2004,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll similarity index 76% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index 1836f4c4b2f..468687b0aca 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -14,16 +18,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -31,14 +27,72 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the register operand with the specified parameters. + */ +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the non-Phi memory operand with the specified parameters. + */ +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) +} + +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); +} + +/** + * Returns the Phi operand with the specified parameters. + */ +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -104,7 +158,17 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** @@ -169,8 +233,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,30 +268,37 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { result = defInstr } final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. @@ -235,15 +306,33 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +/** + * A memory operand other than the operand of a `Phi` instruction. + */ +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } - final override Overlap getDefinitionOverlap() { result = overlap } + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -258,8 +347,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +355,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +363,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +370,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +377,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +384,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +391,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +398,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } -} - -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } } /** @@ -342,8 +405,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +422,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +429,30 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -427,8 +482,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -438,7 +491,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll similarity index 86% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index d9c0df44e12..b3e3a5b1195 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -47,7 +58,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +235,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll similarity index 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll index 196949579f7..aac2e679a97 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll new file mode 100644 index 00000000000..6e2340af7ea --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll similarity index 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..796fb792366 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll @@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" + this instanceof TConstantValueNumber and result = "Constant" or this instanceof TStringConstantValueNumber and result = "StringConstant" or diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll new file mode 100644 index 00000000000..34bd754692d --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll new file mode 100644 index 00000000000..c80761a68cf --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll similarity index 87% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index d2f23a8c15f..64d17f539c9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -1,9 +1,11 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.Overlap -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.internal.IRFunctionBase +private import experimental.ir.implementation.internal.TInstruction +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.Overlap +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedElement @@ -11,30 +13,44 @@ private import TranslatedExpr private import TranslatedStmt private import desugar.Foreach private import TranslatedFunction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, result) +} -import Cached +pragma[noinline] +private predicate instructionOrigin( + Instruction instruction, TranslatedElement element, InstructionTag tag +) { + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) +} +class TStageInstruction = TRawInstruction; + +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { - cached - predicate functionHasIR(Callable callable) { - exists(getTranslatedFunction(callable)) and - callable.fromSource() - } +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) } + + cached + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) + } cached predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { @@ -66,18 +82,6 @@ private module Cached { none() } - cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - cached Expr getInstructionConvertedResultExpression(Instruction instruction) { exists(TranslatedExpr translatedExpr | @@ -94,6 +98,98 @@ private module Cached { ) } + cached + IRVariable getInstructionVariable(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) + } + + cached + Field getInstructionField(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionField(tag) + ) + } + + cached + int getInstructionIndex(Instruction instruction) { none() } + + cached + Callable getInstructionFunction(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionFunction(getInstructionTag(instruction)) + } + + cached + string getInstructionConstantValue(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionConstantValue(getInstructionTag(instruction)) + } + + cached + CSharpType getInstructionExceptionType(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionExceptionType(getInstructionTag(instruction)) + } + + cached + predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + getInstructionTranslatedElement(instruction) + .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) + } + + cached + int getInstructionElementSize(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionElementSize(tag) + ) + } + + cached + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } +} + +import Cached + +cached +private module Cached { + cached + Opcode getInstructionOpcode(TRawInstruction instr) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(result, tag, _) + ) + } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) { + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() + } + + cached + predicate hasInstruction(TRawInstruction instr) { any() } + + cached + predicate hasModeledMemoryResult(Instruction instruction) { none() } + + cached + predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal + } + cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { result = @@ -269,37 +365,6 @@ private module Cached { .hasInstruction(_, getInstructionTag(instruction), result) } - cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and - ( - result = element.getInstructionVariable(tag) or - result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) - ) - ) - } - - cached - Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) - } - cached ArrayAccess getInstructionArrayAccess(Instruction instruction) { result = @@ -307,52 +372,6 @@ private module Cached { .getInstructionArrayAccess(getInstructionTag(instruction)) } - cached - int getInstructionIndex(Instruction instruction) { none() } - - cached - Callable getInstructionFunction(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionFunction(getInstructionTag(instruction)) - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionConstantValue(getInstructionTag(instruction)) - } - - cached - CSharpType getInstructionExceptionType(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionExceptionType(getInstructionTag(instruction)) - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { - getInstructionTranslatedElement(instruction) - .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) - } - - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - - cached - int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) - } - cached int getInstructionResultSize(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | @@ -368,9 +387,6 @@ private module Cached { result = element.getPrimaryInstructionForSideEffect(tag) ) } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } } import CachedForDebugging diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..4e9a7d9f3ae --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll new file mode 100644 index 00000000000..14dad7400b2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll new file mode 100644 index 00000000000..e44184dd76c --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import IRConstruction as Construction +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll new file mode 100644 index 00000000000..bdb4377cbdc --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll new file mode 100644 index 00000000000..4bcd2e127c1 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll @@ -0,0 +1,6 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll index 818d37cf803..b97981876d4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.ir.Util +import experimental.ir.Util private predicate elementIsInitialized(int elementIndex) { exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex)) @@ -29,8 +29,6 @@ newtype TInstructionTag = ReturnValueAddressTag() or ReturnTag() or ExitFunctionTag() or - UnmodeledDefinitionTag() or - UnmodeledUseTag() or AliasedDefinitionTag() or AliasedUseTag() or SwitchBranchTag() or @@ -126,10 +124,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = ExitFunctionTag() and result = "ExitFunc" or - tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" - or - tag = UnmodeledUseTag() and result = "UnmodeledUse" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = AliasedUseTag() and result = "AliasedUse" diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll new file mode 100644 index 00000000000..40af4631927 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll new file mode 100644 index 00000000000..9a3e4c03646 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll @@ -0,0 +1 @@ +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll similarity index 87% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll index f84b32aa285..a2c6a708c72 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll @@ -1,13 +1,13 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The IR translation of a call to a function. The function can be a normal function @@ -17,10 +17,6 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language */ abstract class TranslatedCall extends TranslatedExpr, TranslatedCallBase { final override Instruction getResult() { result = TranslatedCallBase.super.getResult() } - - override Instruction getUnmodeledDefinitionInstruction() { - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll similarity index 95% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll index cc398a86011..a172800b377 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import common.TranslatedConditionBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll similarity index 89% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll index 9cd0a0a34fc..86cbdbb4360 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language private import common.TranslatedDeclarationBase /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 141c04b9927..0022711f79e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -1,17 +1,17 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.IRConfiguration -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.IRConfiguration +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt private import IRConstruction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language private import desugar.Foreach private import desugar.Delegate private import desugar.Lock @@ -21,6 +21,16 @@ ArrayType getArrayOfDim(int dim, Type type) { result.getElementType() = type } +IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) { generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1] or @@ -117,6 +127,7 @@ private predicate ignoreExpr(Expr expr) { private predicate translateFunction(Callable callable) { // not isInvalidFunction(callable) exists(callable.getEntryPoint()) and + callable.fromSource() and exists(IRConfiguration config | config.shouldCreateIRForFunction(callable)) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 2ccac5af4e0..72c408a3f2a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1,9 +1,9 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -16,8 +16,8 @@ private import common.TranslatedExprBase private import desugar.Delegate private import desugar.internal.TranslatedCompilerGeneratedCall import TranslatedCall -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the TranslatedExpr for the specified expression. If `expr` is a load, @@ -201,13 +201,8 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) or tag = ConditionValueResultLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ConditionValueResultTempAddressTag()) } override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { @@ -282,13 +277,8 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getOperand().getResult() } final override predicate producesExprResult() { @@ -351,13 +341,8 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = CrementLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getOperand().getResult() or tag = CrementOpTag() and ( @@ -784,13 +769,8 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { this.needsExtraLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(AddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(AddressTag()) } final override Instruction getChildSuccessor(TranslatedElement child) { @@ -1477,13 +1457,8 @@ class TranslatedAssignOperation extends TranslatedAssignment { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = AssignOperationLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getLeftOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getLeftOperand().getResult() or this.leftOperandNeedsConversion() and tag = AssignOperationConvertLeftTag() and @@ -1626,13 +1601,8 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) or tag = ConditionValueResultLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) } @@ -1902,13 +1872,8 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = this.getInstruction(InitializerVariableAddressTag()) or tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(InitializerVariableAddressTag()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -2024,13 +1989,8 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { this.needsLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(NewObjTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(NewObjTag()) } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll index 9d63f7060e9..65488a1b95d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,16 +1,16 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization private import TranslatedStmt -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the `TranslatedFunction` that represents function `callable`. @@ -66,11 +66,8 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = EnterFunctionTag() and result = this.getInstruction(AliasedDefinitionTag()) or - tag = AliasedDefinitionTag() and - result = this.getInstruction(UnmodeledDefinitionTag()) - or ( - tag = UnmodeledDefinitionTag() and + tag = AliasedDefinitionTag() and if exists(getThisType()) then result = this.getInstruction(InitializeThisTag()) else @@ -93,13 +90,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = this.getInstruction(ReturnTag()) or tag = ReturnTag() and - result = this.getInstruction(UnmodeledUseTag()) + result = this.getInstruction(AliasedUseTag()) or tag = UnwindTag() and - result = this.getInstruction(UnmodeledUseTag()) - or - tag = UnmodeledUseTag() and - result = getInstruction(AliasedUseTag()) + result = this.getInstruction(AliasedUseTag()) or tag = AliasedUseTag() and result = this.getInstruction(ExitFunctionTag()) @@ -136,10 +130,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::EnterFunction and resultType = getVoidType() or - tag = UnmodeledDefinitionTag() and - opcode instanceof Opcode::UnmodeledDefinition and - resultType = getUnknownType() - or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and resultType = getUnknownType() @@ -171,10 +161,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { exists(ThrowStmt throw | throw.getEnclosingCallable() = callable) ) or - tag = UnmodeledUseTag() and - opcode instanceof Opcode::UnmodeledUse and - resultType = getVoidType() - or tag = AliasedUseTag() and opcode instanceof Opcode::AliasedUse and resultType = getVoidType() @@ -190,28 +176,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result.getEnclosingFunction() = callable and - result.hasMemoryResult() - or - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result = getUnmodeledDefinitionInstruction() - or - tag = AliasedUseTag() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() - or tag = ReturnTag() and not this.getReturnType() instanceof VoidType and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ReturnValueAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ReturnValueAddressTag()) } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { @@ -253,13 +221,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getIRTempVariable(callable, ReturnValueTempVar()) } - /** - * Gets the single `UnmodeledDefinition` instruction for this function. - */ - final Instruction getUnmodeledDefinitionInstruction() { - result = this.getInstruction(UnmodeledDefinitionTag()) - } - /** * Gets the single `InitializeThis` instruction for this function. Holds only * if the function is an instance member function, constructor, or destructor. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll similarity index 98% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll index c8576c42369..cbe0e7c1d2a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedFunction -private import semmle.code.csharp.ir.Util +private import experimental.ir.Util private import IRInternal private import desugar.Delegate diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll similarity index 98% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll index 0ec51bd9190..81de9a6b7c9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -11,7 +11,7 @@ private import TranslatedFunction private import TranslatedInitialization private import common.TranslatedConditionBase private import IRInternal -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.internal.IRUtilities private import desugar.Foreach private import desugar.Lock @@ -453,14 +453,8 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = ThrowTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = - getTranslatedFunction(stmt.getEnclosingCallable()).getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(InitializerVariableAddressTag()) } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll similarity index 85% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll index db02eadd419..a870ed02648 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.Util +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase abstract class TranslatedCallBase extends TranslatedElement { @@ -104,11 +104,6 @@ abstract class TranslatedCallBase extends TranslatedElement { result = getArgument(argTag.getArgIndex()).getResult() ) ) - or - tag = CallSideEffectTag() and - hasSideEffect() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { @@ -125,12 +120,6 @@ abstract class TranslatedCallBase extends TranslatedElement { */ abstract Type getCallResultType(); - /** - * Gets the unmodeled definition instruction of the enclosing - * function (of the element this call is attached to). - */ - abstract Instruction getUnmodeledDefinitionInstruction(); - /** * Holds if the call has a `this` argument. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll similarity index 80% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 8d4c5202d34..6f8e2df02ee 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -3,14 +3,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Represents the context of the condition, ie. provides diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index 549b554ee94..9fd47de9060 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -4,15 +4,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedInitialization +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll similarity index 68% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll index d0046d0862a..ec6a8c0ab00 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll @@ -3,8 +3,8 @@ * (both AST generated and compiler generated). */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedExprBase extends TranslatedElement { /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll similarity index 87% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll index fc8665efedf..267cf903b00 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll @@ -6,22 +6,22 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.InstructionTag private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedExpr private import internal.TranslatedCompilerGeneratedCondition private import internal.TranslatedCompilerGeneratedCall private import internal.TranslatedCompilerGeneratedElement private import internal.TranslatedCompilerGeneratedDeclaration -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The general form of a compiler generated try stmt. @@ -217,13 +217,8 @@ abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompi override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { needsLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = getInstruction(AddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = getInstruction(AddressTag()) } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll index 99938ec1478..939f14ba8fe 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll @@ -9,18 +9,18 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedCall -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase /** * Module that exposes the functions needed for the translation of the delegate creation and call expressions. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll similarity index 94% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll index 3d01b56e49e..9dee8221235 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll @@ -5,13 +5,13 @@ * Also we only deal with foreach stmts where there is only * one declaration (see below). * For example the code: - * ``` + * ```csharp * foreach(var item in some_enumerable) { * // body * } * ``` * gets desugared to: - * ``` + * ```csharp * Enumerator e = some_enumerable.GetEnumerator(); * try * { @@ -34,17 +34,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll similarity index 93% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll index 7a0ec9d5cbc..c83957d9b94 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll @@ -1,11 +1,11 @@ /** * File that provides the desugaring of a `lock` stmt. * The statement: - * ``` + * ```csharp * lock (anExpr) ... * ``` * gets desugared to: - * ``` + * ```csharp * SomeRefType lockedVar = anExpr; * bool __lockWasTaken = false; * try { @@ -19,17 +19,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll new file mode 100644 index 00000000000..28dfd2b4cc3 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll @@ -0,0 +1,17 @@ +/** + * Contains an abstract class that is the super class of the classes that deal with compiler generated calls. + */ + +import csharp +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase +private import TranslatedCompilerGeneratedElement +private import experimental.ir.internal.IRCSharpLanguage as Language + +abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, + TranslatedCompilerGeneratedElement { + final override string toString() { + result = "compiler generated call (" + generatedBy.toString() + ")" + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll similarity index 63% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll index 635db767078..df0bf1b24c6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll @@ -3,10 +3,10 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement, ValueConditionBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index b13702ac168..273c9936588 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -5,15 +5,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll index 299b2547c19..1eb7520eda4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll @@ -3,8 +3,8 @@ * which represents the element that generated the compiler generated element. */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, TTranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll similarity index 65% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll index 1c0ad500fc6..b7988c3fde8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll @@ -5,9 +5,9 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.implementation.raw.Instruction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.Instruction +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement, TranslatedExprBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll index 68ec2f102fe..70955e02c9b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll @@ -5,7 +5,7 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement { final override string toString() { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..93131e2abb5 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll new file mode 100644 index 00000000000..3fa0f1b78be --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -0,0 +1,75 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + +import IRFunction +import Instruction +import IRBlock +import IRVariable +import Operand +private import internal.IRImports as Imports +import Imports::EdgeKind +import Imports::IRType +import Imports::MemoryAccessKind + +private newtype TIRPropertyProvider = MkIRPropertyProvider() + +/** + * A class that provides additional properties to be dumped for IR instructions and blocks when using + * the PrintIR module. Libraries that compute additional facts about IR elements can extend the + * single instance of this class to specify the additional properties computed by the library. + */ +class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ + string toString() { result = "IRPropertyProvider" } + + /** + * Gets the value of the property named `key` for the specified instruction. + */ + string getInstructionProperty(Instruction instruction, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified block. + */ + string getBlockProperty(IRBlock block, string key) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll similarity index 71% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index dce1717bdc9..d827ed3cf82 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,49 +20,89 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -70,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -91,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -206,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..909a7a5fc24 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll new file mode 100644 index 00000000000..6a87b9b4b5f --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(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) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + 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 and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + 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, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * 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, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * 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, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + 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 + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll similarity index 61% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll index 1e9c2d1d913..5968e58f90b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ @@ -40,16 +28,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll similarity index 76% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index 0d5e7fe595c..146fc270738 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,10 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } +} + +/** + * A temporary variable generated to hold the `this` pointer. + */ +class IRThisVariable extends IRTempVariable, IRParameter { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -240,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -257,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -265,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 780f636ff10..0fd31dbd9c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -320,8 +343,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -393,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -408,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -475,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -497,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -506,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -542,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is true. + */ + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -635,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -779,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -858,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -868,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -878,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -888,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -898,16 +1466,33 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + /** Gets the successor instruction along the default edge of the switch, if any. */ + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -937,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -982,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -997,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1047,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1057,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1088,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1104,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1112,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1119,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1212,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1230,10 +1854,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ @@ -1248,12 +1868,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * @@ -1351,26 +1965,33 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1383,3 +2004,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll similarity index 76% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll index 1836f4c4b2f..468687b0aca 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -14,16 +18,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -31,14 +27,72 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the register operand with the specified parameters. + */ +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** + * Returns the non-Phi memory operand with the specified parameters. + */ +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) +} + +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); +} + +/** + * Returns the Phi operand with the specified parameters. + */ +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -104,7 +158,17 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** @@ -169,8 +233,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,30 +268,37 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { result = defInstr } final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. @@ -235,15 +306,33 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +/** + * A memory operand other than the operand of a `Phi` instruction. + */ +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } - final override Overlap getDefinitionOverlap() { result = overlap } + final override string toString() { result = tag.toString() } + + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -258,8 +347,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +355,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +363,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +370,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +377,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +384,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +391,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +398,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } -} - -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } } /** @@ -342,8 +405,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +422,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +429,30 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -427,8 +482,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -438,7 +491,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll similarity index 86% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..b3e3a5b1195 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -47,7 +58,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +235,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index f9e1cc7f412..c50e8385c99 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll new file mode 100644 index 00000000000..c70b240fe42 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll similarity index 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..796fb792366 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" + this instanceof TConstantValueNumber and result = "Constant" or this instanceof TStringConstantValueNumber and result = "StringConstant" or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll new file mode 100644 index 00000000000..34bd754692d --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..19fb0490f80 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and @@ -247,6 +248,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index 11d7d37063e..7992aa9ed14 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -1,6 +1,6 @@ private import csharp -import semmle.code.csharp.ir.implementation.IRConfiguration -import semmle.code.csharp.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.IRConfiguration +import experimental.ir.internal.IntegerConstant as Ints module AliasModels { /** @@ -12,7 +12,7 @@ module AliasModels { * the function returns. * * Example: - * ``` + * ```csharp * int* g; * int* func(int* p, int* q, int* r, int* s, int n) { * *s = 1; // `s` does not escape. diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll new file mode 100644 index 00000000000..f3f2d14ab43 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR as InputIR +import AliasConfiguration as Configuration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll new file mode 100644 index 00000000000..fc29c0d77dd --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.raw.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll new file mode 100644 index 00000000000..c80761a68cf --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..4e9a7d9f3ae --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll new file mode 100644 index 00000000000..14dad7400b2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll new file mode 100644 index 00000000000..eaf33e0800f --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import SSAConstruction as Construction +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll new file mode 100644 index 00000000000..bdb4377cbdc --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll new file mode 100644 index 00000000000..4bcd2e127c1 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -0,0 +1,6 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll new file mode 100644 index 00000000000..40af4631927 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll new file mode 100644 index 00000000000..9a3e4c03646 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -0,0 +1 @@ +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..cee1274eb19 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id csharp/unaliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 155934689b6..ae0e03e97da 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,47 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -67,15 +66,13 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -83,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -127,40 +124,13 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap @@ -201,13 +171,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -220,7 +192,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -232,21 +204,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -257,20 +219,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -289,137 +251,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() + or + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + instr = unreachedInstruction(_) and result = Language::getVoidType() + } + + cached + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() + or + instr = phiInstruction(_, _) and result instanceof Opcode::Phi + or + instr = chiInstruction(_) and result instanceof Opcode::Chi + or + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached + } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() + or + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(_) and - result = Language::getVoidType() - } - - cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) or - instruction instanceof Chi and - result instanceof Opcode::Chi - or - instruction instanceof Phi and - result instanceof Opcode::Phi - or - instruction instanceof Unreached and - result instanceof Opcode::Unreached - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) - or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) - or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) + instr = unreachedInstruction(result) } cached @@ -430,7 +328,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -438,6 +336,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -617,7 +523,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -636,7 +542,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -920,7 +826,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -930,7 +836,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -941,7 +847,10 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -954,6 +863,9 @@ module SSASanity { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -962,4 +874,41 @@ module SSASanity { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } +} + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll new file mode 100644 index 00000000000..bf9b18d0b17 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.TInstruction as TInstruction +import experimental.ir.implementation.raw.IR as RawIR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll new file mode 100644 index 00000000000..15eaf8045a7 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -0,0 +1,8 @@ +import experimental.ir.implementation.raw.IR as OldIR +import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance +import experimental.ir.implementation.unaliased_ssa.IR as NewIR +import experimental.ir.implementation.raw.internal.IRConstruction as RawStage +import experimental.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions +import experimental.ir.internal.IRCSharpLanguage as Language +import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll new file mode 100644 index 00000000000..80a1c7c36fd --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.raw.IR +import experimental.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.internal.OperandTag +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll new file mode 100644 index 00000000000..047d4923039 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll @@ -0,0 +1 @@ +import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..e435289cbfc --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/experimental/ir/internal/CSharpType.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll rename to csharp/ql/src/experimental/ir/internal/CSharpType.qll index fdd7ef804d2..02dee3edff9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/experimental/ir/internal/CSharpType.qll @@ -1,5 +1,5 @@ private import csharp -private import semmle.code.csharp.ir.implementation.IRType +private import experimental.ir.implementation.IRType private import IRCSharpLanguage as Language int getTypeSize(Type type) { @@ -368,7 +368,7 @@ CSharpPRValueType getCanonicalOpaqueType(Type tag, int byteSize) { getTypeSize(tag) = byteSize } -module LanguageTypeSanity { +module LanguageTypeConsistency { // Nothing interesting here for C# yet, but the module still has to exist because it is imported - // by `IRTypeSanity`. + // by `IRTypeConsistency`. } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll rename to csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll rename to csharp/ql/src/experimental/ir/internal/IRGuards.qll index 0cafb65d6f2..a505e54c37e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll +++ b/csharp/ql/src/experimental/ir/internal/IRGuards.qll @@ -1,6 +1,6 @@ import csharp import semmle.code.csharp.controlflow.BasicBlocks -import semmle.code.csharp.ir.IR +import experimental.ir.IR /** * Holds if `block` consists of an `UnreachedInstruction`. @@ -93,7 +93,7 @@ class GuardCondition extends Expr { * implies that the truth of the child expression `part` has truth value `partIsTrue`. * * For example if the binary operation: - * ``` + * ```csharp * x && y * ``` * is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and @@ -341,7 +341,7 @@ class IRGuardCondition extends Instruction { * predecessors. For example, in the following situation, an inference can be made about the * value of `x` at the end of the `if` statement, but there is no block which is controlled by * the `if` statement when `x >= y`. - * ``` + * ```csharp * if (x < y) { * x = y; * } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll b/csharp/ql/src/experimental/ir/internal/IRUtilities.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll rename to csharp/ql/src/experimental/ir/internal/IRUtilities.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll similarity index 92% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll rename to csharp/ql/src/experimental/ir/internal/IntegerConstant.qll index 6034ebc5674..4af31745ab2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll +++ b/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll @@ -1,3 +1,15 @@ +/** + * Provides predicates for manipulating integer constants that are tracked by constant folding and + * similar analyses. + */ + +/** + * An alias used to represent the constant value of an integer, if one can be determined. If no + * single constant value can be determined, or if the constant value is out of the representable + * range, it will be represented as the special value `unknown()`. This allows `IntValue` to be used + * in contexts where there must always be a value for the `IntValue`, even if no constant value is + * known. + */ class IntValue = int; /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll b/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll rename to csharp/ql/src/experimental/ir/internal/IntegerInterval.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll b/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll rename to csharp/ql/src/experimental/ir/internal/IntegerPartial.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll b/csharp/ql/src/experimental/ir/internal/Overlap.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll rename to csharp/ql/src/experimental/ir/internal/Overlap.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll b/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll similarity index 89% rename from csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll rename to csharp/ql/src/experimental/ir/internal/TempVariableTag.qll index dec457bcec7..8950c2cd8a8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll +++ b/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll @@ -8,7 +8,8 @@ newtype TTempVariableTag = ForeachEnumTempVar() or LockedVarTemp() or LockWasTakenTemp() or - EllipsisTempVar() + EllipsisTempVar() or + ThisTempVar() string getTempVariableTagId(TTempVariableTag tag) { tag = ConditionValueTempVar() and result = "CondVal" @@ -26,4 +27,6 @@ string getTempVariableTagId(TTempVariableTag tag) { tag = LockWasTakenTemp() and result = "LockWasTakenTemp" or tag = EllipsisTempVar() and result = "Ellipsis" + or + tag = ThisTempVar() and result = "This" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll index 8cde0baddfc..c79c199832b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll @@ -1,6 +1,6 @@ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.ValueNumbering private newtype TBound = TBoundZero() or diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll index e3403728633..ccc6b9ea30e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll @@ -10,7 +10,7 @@ /* * This library tackles range analysis as a flow problem. Consider e.g.: - * ``` + * ```csharp * len = arr.length; * if (x < len) { ... y = x-1; ... y ... } * ``` @@ -68,9 +68,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import RangeUtils private import SignAnalysis import Bound diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll index f3b94c4ef01..4a7f1d69840 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.IR +private import experimental.ir.IR // TODO: move this dependency -import semmle.code.csharp.ir.internal.IntegerConstant +import experimental.ir.internal.IntegerConstant // TODO: move this out of test code language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll similarity index 98% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll index 1cba4d7e732..44548e0517a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll @@ -7,9 +7,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import SignAnalysisCached private newtype TSign = @@ -278,8 +278,6 @@ private predicate unknownSign(Instruction i) { // non-positive, non-zero}, which would mean that the representation of the sign of an unknown // value would be the empty set. ( - i instanceof UnmodeledDefinitionInstruction - or i instanceof UninitializedInstruction or i instanceof InitializeParameterInstruction diff --git a/csharp/ql/src/localDefinitions.ql b/csharp/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..56648e666d0 --- /dev/null +++ b/csharp/ql/src/localDefinitions.ql @@ -0,0 +1,19 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id cs/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Use e, Declaration def, string kind, string filepath +where + def = definitionOf(e, kind) and + e.hasLocationInfo(filepath, _, _, _, _) and + filepath = getEncodedFile(selectedSourceFile()).getAbsolutePath() +select e, def, kind diff --git a/csharp/ql/src/localReferences.ql b/csharp/ql/src/localReferences.ql new file mode 100644 index 00000000000..3e6d0a7c236 --- /dev/null +++ b/csharp/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id cs/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Use e, Declaration def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/csharp/ql/src/semmle/code/asp/AspNet.qll b/csharp/ql/src/semmle/code/asp/AspNet.qll index c7ed51bb484..0666c5eb782 100644 --- a/csharp/ql/src/semmle/code/asp/AspNet.qll +++ b/csharp/ql/src/semmle/code/asp/AspNet.qll @@ -32,7 +32,7 @@ class AspAttribute extends AspElement, @asp_attribute { } /** * An open tag, for example the tag on line 1 in * - * ``` + * ```html * @@ -67,7 +67,7 @@ class AspOpenTag extends AspElement, @asp_open_tag { /** * A close tag, for example the tag on line 3 in * - * ``` + * ```html * @@ -123,7 +123,7 @@ class AspServerComment extends AspComment { /** * A data-binding expression, for example `<%# myArray %>` in * - * ``` + * ```html * * ``` */ diff --git a/csharp/ql/src/semmle/code/cil/BasicBlock.qll b/csharp/ql/src/semmle/code/cil/BasicBlock.qll index ef584e73bbe..459bb667e6f 100644 --- a/csharp/ql/src/semmle/code/cil/BasicBlock.qll +++ b/csharp/ql/src/semmle/code/cil/BasicBlock.qll @@ -23,7 +23,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -41,7 +41,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -75,7 +75,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -97,7 +97,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -124,7 +124,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -158,7 +158,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -182,7 +182,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -207,7 +207,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -353,7 +353,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -361,7 +361,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/cil/Instructions.qll b/csharp/ql/src/semmle/code/cil/Instructions.qll index 3f3011f10b3..15bf4f9a725 100644 --- a/csharp/ql/src/semmle/code/cil/Instructions.qll +++ b/csharp/ql/src/semmle/code/cil/Instructions.qll @@ -1,90 +1,106 @@ /** * Provides classes representing individual opcodes. + * + * See ECMA-335 (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf) + * pages 32-101 for a detailed explanation of these instructions. */ private import CIL private import semmle.code.dotnet.Variable as DotNet module Opcodes { - // Literals + /** An `ldc.i4.m1` instruction. */ class Ldc_i4_m1 extends IntLiteral, @cil_ldc_i4_m1 { override string getOpcodeName() { result = "ldc.i4.m1" } override string getValue() { result = "-1" } } + /** An `ldc.i4.0` instruction. */ class Ldc_i4_0 extends IntLiteral, @cil_ldc_i4_0 { override string getOpcodeName() { result = "ldc.i4.0" } override string getValue() { result = "0" } } + /** An `ldc.i4.1` instruction. */ class Ldc_i4_1 extends IntLiteral, @cil_ldc_i4_1 { override string getOpcodeName() { result = "ldc.i4.1" } override string getValue() { result = "1" } } + /** An `ldc.i4.2` instruction. */ class Ldc_i4_2 extends IntLiteral, @cil_ldc_i4_2 { override string getOpcodeName() { result = "ldc.i4.2" } override string getValue() { result = "2" } } + /** An `ldc.i4.3` instruction. */ class Ldc_i4_3 extends IntLiteral, @cil_ldc_i4_3 { override string getOpcodeName() { result = "ldc.i4.3" } override string getValue() { result = "3" } } + /** An `ldc.i4.4` instruction. */ class Ldc_i4_4 extends IntLiteral, @cil_ldc_i4_4 { override string getOpcodeName() { result = "ldc.i4.4" } override string getValue() { result = "4" } } + /** An `ldc.i4.5` instruction. */ class Ldc_i4_5 extends IntLiteral, @cil_ldc_i4_5 { override string getOpcodeName() { result = "ldc.i4.5" } override string getValue() { result = "5" } } + /** An `ldc.i4.6` instruction. */ class Ldc_i4_6 extends IntLiteral, @cil_ldc_i4_6 { override string getOpcodeName() { result = "ldc.i4.6" } override string getValue() { result = "6" } } + /** An `ldc.i4.7` instruction. */ class Ldc_i4_7 extends IntLiteral, @cil_ldc_i4_7 { override string getOpcodeName() { result = "ldc.i4.7" } override string getValue() { result = "7" } } + /** An `ldc.i4.8` instruction. */ class Ldc_i4_8 extends IntLiteral, @cil_ldc_i4_8 { override string getOpcodeName() { result = "ldc.i4.8" } override string getValue() { result = "8" } } + /** An `ldc.i4` instruction. */ class Ldc_i4 extends IntLiteral, @cil_ldc_i4 { override string getOpcodeName() { result = "ldc.i4" } override string getExtra() { result = getValue() } } + /** An `ldc.i8` instruction. */ class Ldc_i8 extends IntLiteral, @cil_ldc_i8 { override string getOpcodeName() { result = "ldc.i8" } override string getExtra() { result = getValue() } } + /** An `ldc.i4.s` instruction. */ class Ldc_i4_s extends IntLiteral, @cil_ldc_i4_s { override string getOpcodeName() { result = "ldc.i4.s" } override string getExtra() { result = getValue() } } + /** An `ldnull` instruction. */ class Ldnull extends Literal, @cil_ldnull { override string getOpcodeName() { result = "ldnull" } @@ -95,6 +111,7 @@ module Opcodes { override Type getType() { result instanceof ObjectType } } + /** An `ldc.r4` instruction. */ class Ldc_r4 extends FloatLiteral, @cil_ldc_r4 { override string getOpcodeName() { result = "ldc.r4" } @@ -103,6 +120,7 @@ module Opcodes { override Type getType() { result instanceof FloatType } } + /** An `ldc.r8` instruction. */ class Ldc_r8 extends FloatLiteral, @cil_ldc_r8 { override string getOpcodeName() { result = "ldc.r8" } @@ -111,59 +129,72 @@ module Opcodes { override Type getType() { result instanceof DoubleType } } - // Arithmetic operations + /** An `add` instruction. */ class Add extends BinaryArithmeticExpr, @cil_add { override string getOpcodeName() { result = "add" } } + /** An `add.ovf` instruction. */ class Add_ovf extends BinaryArithmeticExpr, @cil_add_ovf { override string getOpcodeName() { result = "add.ovf" } } + /** An `add.ovf.un` instruction. */ class Add_ovf_un extends BinaryArithmeticExpr, @cil_add_ovf_un { override string getOpcodeName() { result = "add.ovf.un" } } + /** A `sub` instruction. */ class Sub extends BinaryArithmeticExpr, @cil_sub { override string getOpcodeName() { result = "sub" } } + /** A `sub.ovf` instruction. */ class Sub_ovf extends BinaryArithmeticExpr, @cil_sub_ovf { override string getOpcodeName() { result = "sub.ovf" } } + /** A `sub.ovf.un` instruction. */ class Sub_ovf_un extends BinaryArithmeticExpr, @cil_sub_ovf_un { override string getOpcodeName() { result = "sub.ovf.un" } } + /** A `mul` instruction. */ class Mul extends BinaryArithmeticExpr, @cil_mul { override string getOpcodeName() { result = "mul" } } + /** A `mul.ovf` instruction. */ class Mul_ovf extends BinaryArithmeticExpr, @cil_mul_ovf { override string getOpcodeName() { result = "mul.ovf" } } + /** A `mul.ovf.un` instruction. */ class Mul_ovf_un extends BinaryArithmeticExpr, @cil_mul_ovf_un { override string getOpcodeName() { result = "mul.ovf.un" } } + /** A `div` instruction. */ class Div extends BinaryArithmeticExpr, @cil_div { override string getOpcodeName() { result = "div" } } + /** A `div.un` instruction. */ class Div_un extends BinaryArithmeticExpr, @cil_div_un { override string getOpcodeName() { result = "div.un" } } + /** A `rem` instruction. */ class Rem extends BinaryArithmeticExpr, @cil_rem { override string getOpcodeName() { result = "rem" } } + /** A `rem.un` instruction. */ class Rem_un extends BinaryArithmeticExpr, @cil_rem_un { override string getOpcodeName() { result = "rem.un" } } + /** A `neg` instruction. */ class Neg extends UnaryExpr, @cil_neg { override string getOpcodeName() { result = "neg" } @@ -174,46 +205,54 @@ module Opcodes { } } - // Binary operations + /** An `and` instruction. */ class And extends BinaryBitwiseOperation, @cil_and { override string getOpcodeName() { result = "and" } } + /** An `or` instruction. */ class Or extends BinaryBitwiseOperation, @cil_or { override string getOpcodeName() { result = "or" } } + /** An `xor` instruction. */ class Xor extends BinaryBitwiseOperation, @cil_xor { override string getOpcodeName() { result = "xor" } } + /** A `not` instruction. */ class Not extends UnaryBitwiseOperation, @cil_not { override string getOpcodeName() { result = "not" } } + /** A `shl` instruction. */ class Shl extends BinaryBitwiseOperation, @cil_shl { override string getOpcodeName() { result = "shl" } } + /** A `shr` instruction. */ class Shr extends BinaryBitwiseOperation, @cil_shr { override string getOpcodeName() { result = "shr" } } + /** A `shr.un` instruction. */ class Shr_un extends BinaryBitwiseOperation, @cil_shr_un { override string getOpcodeName() { result = "shr.un" } } - // Binary comparison operations + /** A `ceq` instruction. */ class Ceq extends ComparisonOperation, @cil_ceq { override string getOpcodeName() { result = "ceq" } } + /** A `pop` instruction. */ class Pop extends Instruction, @cil_pop { override string getOpcodeName() { result = "pop" } override int getPopCount() { result = 1 } } + /** A `dup` instruction. */ class Dup extends Expr, @cil_dup { override string getOpcodeName() { result = "dup" } @@ -224,6 +263,7 @@ module Opcodes { override Type getType() { result = getOperand(0).getType() } } + /** A `ret` instruction. */ class Ret extends Return, @cil_ret { override string getOpcodeName() { result = "ret" } @@ -234,10 +274,12 @@ module Opcodes { } } + /** A `nop` instruction. */ class Nop extends Instruction, @cil_nop { override string getOpcodeName() { result = "nop" } } + /** An `ldstr` instruction. */ class Ldstr extends StringLiteral, @cil_ldstr { override string getOpcodeName() { result = "ldstr" } @@ -246,111 +288,137 @@ module Opcodes { override Type getType() { result instanceof StringType } } - // Control flow + /** A `br` instruction. */ class Br extends UnconditionalBranch, @cil_br { override string getOpcodeName() { result = "br" } } + /** A `br.s` instruction. */ class Br_s extends UnconditionalBranch, @cil_br_s { override string getOpcodeName() { result = "br.s" } } + /** A `brfalse.s` instruction. */ class Brfalse_s extends UnaryBranch, @cil_brfalse_s { override string getOpcodeName() { result = "brfalse.s" } } + /** A `brfalse` instruction. */ class Brfalse extends UnaryBranch, @cil_brfalse { override string getOpcodeName() { result = "brfalse" } } + /** A `brtrue.s` instruction. */ class Brtrue_s extends UnaryBranch, @cil_brtrue_s { override string getOpcodeName() { result = "brtrue.s" } } + /** A `brtrue` instruction. */ class Brtrue extends UnaryBranch, @cil_brtrue { override string getOpcodeName() { result = "brtrue" } } + /** A `blt.s` instruction. */ class Blt_s extends BinaryBranch, @cil_blt_s { override string getOpcodeName() { result = "blt.s" } } + /** A `blt` instruction. */ class Blt extends BinaryBranch, @cil_blt { override string getOpcodeName() { result = "blt" } } + /** A `blt.un.s` instruction. */ class Blt_un_s extends BinaryBranch, @cil_blt_un_s { override string getOpcodeName() { result = "blt.un.s" } } + /** A `blt.un` instruction. */ class Blt_un extends BinaryBranch, @cil_blt_un { override string getOpcodeName() { result = "blt.un" } } + /** A `bgt.un` instruction. */ class Bgt_un extends BinaryBranch, @cil_bgt_un { override string getOpcodeName() { result = "bgt.un" } } + /** A `ble.un.s` instruction. */ class Ble_un_s extends BinaryBranch, @cil_ble_un_s { override string getOpcodeName() { result = "ble.un.s" } } + /** A `ble.un` instruction. */ class Ble_un extends BinaryBranch, @cil_ble_un { override string getOpcodeName() { result = "ble.un" } } + /** A `bge.s` instruction. */ class Bge_s extends BinaryBranch, @cil_bge_s { override string getOpcodeName() { result = "bge.s" } } + /** A `ble.un` instruction. */ class Bge_un extends BinaryBranch, @cil_bge_un { override string getOpcodeName() { result = "bge.un" } } + /** A `bge` instruction. */ class Bge extends BinaryBranch, @cil_bge { override string getOpcodeName() { result = "bge" } } + /** A `bne.un.s` instruction. */ class Bne_un_s extends BinaryBranch, @cil_bne_un_s { override string getOpcodeName() { result = "bne.un.s" } } + /** A `bne.un` instruction. */ class Bne_un extends BinaryBranch, @cil_bne_un { override string getOpcodeName() { result = "bne.un" } } + /** A `beq` instruction. */ class Beq extends BinaryBranch, @cil_beq { override string getOpcodeName() { result = "beq" } } + /** A `beq.s` instruction. */ class Beq_s extends BinaryBranch, @cil_beq_s { override string getOpcodeName() { result = "beq.s" } } + /** A `ble.s` instruction. */ class Ble_s extends BinaryBranch, @cil_ble_s { override string getOpcodeName() { result = "ble.s" } } + /** A `ble` instruction. */ class Ble extends BinaryBranch, @cil_ble { override string getOpcodeName() { result = "ble" } } + /** A `bgt.s` instruction. */ class Bgt_s extends BinaryBranch, @cil_bgt_s { override string getOpcodeName() { result = "bgt.s" } } + /** A `bgt` instruction. */ class Bgt extends BinaryBranch, @cil_bgt { override string getOpcodeName() { result = "bgt" } } + /** A `bgt.in.s` instruction. */ class Bgt_in_s extends BinaryBranch, @cil_bgt_un_s { - override string getOpcodeName() { result = "bgt.un.s" } + override string getOpcodeName() { result = "bgt.in.s" } } + /** A `bge.in.s` instruction. */ class Bge_in_s extends BinaryBranch, @cil_bge_un_s { override string getOpcodeName() { result = "bge.un.s" } } + /** A `switch` instruction. */ class Switch extends ConditionalBranch, @cil_switch { override string getOpcodeName() { result = "switch" } @@ -367,62 +435,73 @@ module Opcodes { } } + /** A `leave` instruction. */ class Leave_ extends Leave, @cil_leave { override string getOpcodeName() { result = "leave" } } + /** A `leave.s` instruction. */ class Leave_s extends Leave, @cil_leave_s { override string getOpcodeName() { result = "leave.s" } } + /** An `endfilter` instruction. */ class Endfilter extends Instruction, @cil_endfilter { override string getOpcodeName() { result = "endfilter" } } + /** An `endfinally` instruction. */ class Endfinally extends Instruction, @cil_endfinally { override string getOpcodeName() { result = "endfinally" } override predicate canFlowNext() { none() } } - // Comparisons (not jumps) + /** A `cgt.un` instruction. */ class Cgt_un extends ComparisonOperation, @cil_cgt_un { override string getOpcodeName() { result = "cgt.un" } } + /** A `cgt` instruction. */ class Cgt extends ComparisonOperation, @cil_cgt { override string getOpcodeName() { result = "cgt" } } + /** A `clt.un` instruction. */ class Clt_un extends ComparisonOperation, @cil_clt_un { - override string getOpcodeName() { result = "cgt.un" } + override string getOpcodeName() { result = "clt.un" } } + /** A `clt` instruction. */ class Clt extends ComparisonOperation, @cil_clt { override string getOpcodeName() { result = "clt" } } - // Calls + /** A `call` instruction. */ class Call_ extends Call, @cil_call { override string getOpcodeName() { result = "call" } } + /** A `callvirt` instruction. */ class Callvirt extends Call, @cil_callvirt { override string getOpcodeName() { result = "callvirt" } override predicate isVirtual() { any() } } + /** A `tail.` instruction. */ class Tail extends Instruction, @cil_tail { override string getOpcodeName() { result = "tail." } } + /** A `jmp` instruction. */ class Jmp extends Call, @cil_jmp { override string getOpcodeName() { result = "jmp" } override predicate isTailCall() { any() } } + /** An `isinst` instruction. */ class Isinst extends UnaryExpr, @cil_isinst { override string getOpcodeName() { result = "isinst" } @@ -434,6 +513,7 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } + /** A `castclass` instruction. */ class Castclass extends UnaryExpr, @cil_castclass { override string getOpcodeName() { result = "castclass" } @@ -445,67 +525,77 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } - // Locals + /** An `stloc.0` instruction. */ class Stloc_0 extends LocalVariableWriteAccess, @cil_stloc_0 { override string getOpcodeName() { result = "stloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `stloc.1` instruction. */ class Stloc_1 extends LocalVariableWriteAccess, @cil_stloc_1 { override string getOpcodeName() { result = "stloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `stloc.2` instruction. */ class Stloc_2 extends LocalVariableWriteAccess, @cil_stloc_2 { override string getOpcodeName() { result = "stloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `stloc.3` instruction. */ class Stloc_3 extends LocalVariableWriteAccess, @cil_stloc_3 { override string getOpcodeName() { result = "stloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `stloc.s` instruction. */ class Stloc_s extends LocalVariableWriteAccess, @cil_stloc_s { override string getOpcodeName() { result = "stloc.s" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `stloc` instruction. */ class Stloc extends LocalVariableWriteAccess, @cil_stloc { override string getOpcodeName() { result = "stloc" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `ldloc.0` instruction. */ class Ldloc_0 extends LocalVariableReadAccess, @cil_ldloc_0 { override string getOpcodeName() { result = "ldloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `ldloc.1` instruction. */ class Ldloc_1 extends LocalVariableReadAccess, @cil_ldloc_1 { override string getOpcodeName() { result = "ldloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `ldloc.2` instruction. */ class Ldloc_2 extends LocalVariableReadAccess, @cil_ldloc_2 { override string getOpcodeName() { result = "ldloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `ldloc.3` instruction. */ class Ldloc_3 extends LocalVariableReadAccess, @cil_ldloc_3 { override string getOpcodeName() { result = "ldloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `ldloc.s` instruction. */ class Ldloc_s extends LocalVariableReadAccess, @cil_ldloc_s { override string getOpcodeName() { result = "ldloc.s" } @@ -514,6 +604,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloca.s` instruction. */ class Ldloca_s extends LocalVariableReadAccess, ReadRefAccess, @cil_ldloca_s { override string getOpcodeName() { result = "ldloca.s" } @@ -522,6 +613,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloc` instruction. */ class Ldloc extends LocalVariableReadAccess, @cil_ldloc { override string getOpcodeName() { result = "ldloc" } @@ -530,31 +622,35 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } - // Arguments + /** An `ldarg.0` instruction. */ class Ldarg_0 extends ParameterReadAccess, @cil_ldarg_0 { override string getOpcodeName() { result = "ldarg.0" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(0) } } + /** An `ldarg.1` instruction. */ class Ldarg_1 extends ParameterReadAccess, @cil_ldarg_1 { override string getOpcodeName() { result = "ldarg.1" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(1) } } + /** An `ldarg.2` instruction. */ class Ldarg_2 extends ParameterReadAccess, @cil_ldarg_2 { override string getOpcodeName() { result = "ldarg.2" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(2) } } + /** An `ldarg.3` instruction. */ class Ldarg_3 extends ParameterReadAccess, @cil_ldarg_3 { override string getOpcodeName() { result = "ldarg.3" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(3) } } + /** An `ldarg.s` instruction. */ class Ldarg_s extends ParameterReadAccess, @cil_ldarg_s { override string getOpcodeName() { result = "ldarg.s" } @@ -563,25 +659,28 @@ module Opcodes { override string getExtra() { result = this.getTarget().getIndex().toString() } } + /** An `ldarg` instruction. */ class Ldarg extends ParameterReadAccess, @cil_ldarg { override string getOpcodeName() { result = "ldarg" } override Parameter getTarget() { cil_access(this, result) } } + /** An `ldarga.s` instruction. */ class Ldarga_s extends ParameterReadAccess, ReadRefAccess, @cil_ldarga_s { override string getOpcodeName() { result = "ldarga.s" } override Parameter getTarget() { cil_access(this, result) } } + /** An `starg.s` instruction. */ class Starg_s extends ParameterWriteAccess, @cil_starg_s { override string getOpcodeName() { result = "starg.s" } override Parameter getTarget() { cil_access(this, result) } } - // Fields + /** An `ldfld` instruction. */ class Ldfld extends FieldReadAccess, @cil_ldfld { override string getOpcodeName() { result = "ldfld" } @@ -590,6 +689,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldflda` instruction. */ class Ldflda extends FieldReadAccess, ReadRefAccess, @cil_ldflda { override string getOpcodeName() { result = "ldflda" } @@ -598,6 +698,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldsfld` instruction. */ class Ldsfld extends FieldReadAccess, @cil_ldsfld { override string getOpcodeName() { result = "ldsfld" } @@ -606,6 +707,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `ldsflda` instruction. */ class Ldsflda extends FieldReadAccess, ReadRefAccess, @cil_ldsflda { override string getOpcodeName() { result = "ldsflda" } @@ -614,6 +716,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `stfld` instruction. */ class Stfld extends FieldWriteAccess, @cil_stfld { override string getOpcodeName() { result = "stfld" } @@ -624,6 +727,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** An `stsfld` instruction. */ class Stsfld extends FieldWriteAccess, @cil_stsfld { override string getOpcodeName() { result = "stsfld" } @@ -634,6 +738,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** A `newobj` instruction. */ class Newobj extends Call, @cil_newobj { override string getOpcodeName() { result = "newobj" } @@ -656,30 +761,35 @@ module Opcodes { } } + /** An `initobj` instruction. */ class Initobj extends Instruction, @cil_initobj { override string getOpcodeName() { result = "initobj" } override int getPopCount() { result = 1 } // ?? } + /** A `box` instruction. */ class Box extends UnaryExpr, @cil_box { override string getOpcodeName() { result = "box" } override Type getType() { result = getAccess() } } + /** An `unbox.any` instruction. */ class Unbox_any extends UnaryExpr, @cil_unbox_any { override string getOpcodeName() { result = "unbox.any" } override Type getType() { result = getAccess() } } + /** An `unbox` instruction. */ class Unbox extends UnaryExpr, @cil_unbox { override string getOpcodeName() { result = "unbox" } override Type getType() { result = getAccess() } } + /** An `ldobj` instruction. */ class Ldobj extends UnaryExpr, @cil_ldobj { override string getOpcodeName() { result = "ldobj" } @@ -689,6 +799,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** An `ldtoken` instruction. */ class Ldtoken extends Expr, @cil_ldtoken { override string getOpcodeName() { result = "ldtoken" } @@ -696,27 +807,31 @@ module Opcodes { override ObjectType getType() { exists(result) } } + /** A `constrained.` instruction. */ class Constrained extends Instruction, @cil_constrained { override string getOpcodeName() { result = "constrained." } } + /** A `throw` instruction. */ class Throw_ extends Throw, @cil_throw { override string getOpcodeName() { result = "throw" } override int getPopCount() { result = 1 } } + /** A `rethrow` instruction. */ class Rethrow extends Throw, @cil_rethrow { override string getOpcodeName() { result = "rethrow" } } + /** A `ldlen` instruction. */ class Ldlen extends UnaryExpr, @cil_ldlen { override string getOpcodeName() { result = "ldlen" } override IntType getType() { exists(result) } } - // Arrays + /** A `newarr` instruction. */ class Newarr extends Expr, @cil_newarr { override string getOpcodeName() { result = "newarr" } @@ -734,449 +849,524 @@ module Opcodes { override string getExtra() { result = getType().getQualifiedName() } } + /** An `ldelem` instruction. */ class Ldelem extends ReadArrayElement, @cil_ldelem { override string getOpcodeName() { result = "ldelem" } override Type getType() { result = getAccess() } } + /** An `ldelem.ref` instruction. */ class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref { override string getOpcodeName() { result = "ldelem.ref" } override Type getType() { result = getArray().getType() } } + /** An `ldelema` instruction. */ class Ldelema extends ReadArrayElement, ReadRef, @cil_ldelema { override string getOpcodeName() { result = "ldelema" } override Type getType() { result = getAccess() } } + /** An `stelem.ref` instruction. */ class Stelem_ref extends WriteArrayElement, @cil_stelem_ref { override string getOpcodeName() { result = "stelem.ref" } } + /** An `stelem` instruction. */ class Stelem extends WriteArrayElement, @cil_stelem { override string getOpcodeName() { result = "stelem" } } + /** An `stelem.i` instruction. */ class Stelem_i extends WriteArrayElement, @cil_stelem_i { override string getOpcodeName() { result = "stelem.i" } } + /** An `stelem.i1` instruction. */ class Stelem_i1 extends WriteArrayElement, @cil_stelem_i1 { override string getOpcodeName() { result = "stelem.i1" } } + /** An `stelem.i2` instruction. */ class Stelem_i2 extends WriteArrayElement, @cil_stelem_i2 { override string getOpcodeName() { result = "stelem.i2" } } + /** An `stelem.i4` instruction. */ class Stelem_i4 extends WriteArrayElement, @cil_stelem_i4 { override string getOpcodeName() { result = "stelem.i4" } } + /** An `stelem.i8` instruction. */ class Stelem_i8 extends WriteArrayElement, @cil_stelem_i8 { override string getOpcodeName() { result = "stelem.i8" } } + /** An `stelem.r4` instruction. */ class Stelem_r4 extends WriteArrayElement, @cil_stelem_r4 { override string getOpcodeName() { result = "stelem.r4" } } + /** An `stelem.r8` instruction. */ class Stelem_r8 extends WriteArrayElement, @cil_stelem_r8 { override string getOpcodeName() { result = "stelem.r8" } } + /** An `ldelem.i` instruction. */ class Ldelem_i extends ReadArrayElement, @cil_ldelem_i { override string getOpcodeName() { result = "ldelem.i" } override IntType getType() { exists(result) } } + /** An `ldelem.i1` instruction. */ class Ldelem_i1 extends ReadArrayElement, @cil_ldelem_i1 { override string getOpcodeName() { result = "ldelem.i1" } override SByteType getType() { exists(result) } } + /** An `ldelem.i2` instruction. */ class Ldelem_i2 extends ReadArrayElement, @cil_ldelem_i2 { override string getOpcodeName() { result = "ldelem.i2" } override ShortType getType() { exists(result) } } + /** An `ldelem.i4` instruction. */ class Ldelem_i4 extends ReadArrayElement, @cil_ldelem_i4 { override string getOpcodeName() { result = "ldelem.i4" } override IntType getType() { exists(result) } } + /** An `ldelem.i8` instruction. */ class Ldelem_i8 extends ReadArrayElement, @cil_ldelem_i8 { override string getOpcodeName() { result = "ldelem.i8" } override LongType getType() { exists(result) } } + /** An `ldelem.r4` instruction. */ class Ldelem_r4 extends ReadArrayElement, @cil_ldelem_r4 { override string getOpcodeName() { result = "ldelem.r4" } override FloatType getType() { exists(result) } } + /** An `ldelem.r8` instruction. */ class Ldelem_r8 extends ReadArrayElement, @cil_ldelem_r8 { override string getOpcodeName() { result = "ldelem.r8" } override DoubleType getType() { exists(result) } } + /** An `ldelem.u1` instruction. */ class Ldelem_u1 extends ReadArrayElement, @cil_ldelem_u1 { override string getOpcodeName() { result = "ldelem.u1" } override ByteType getType() { exists(result) } } + /** An `ldelem.u2` instruction. */ class Ldelem_u2 extends ReadArrayElement, @cil_ldelem_u2 { override string getOpcodeName() { result = "ldelem.u2" } override UShortType getType() { exists(result) } } + /** An `ldelem.u4` instruction. */ class Ldelem_u4 extends ReadArrayElement, @cil_ldelem_u4 { override string getOpcodeName() { result = "ldelem.u4" } override UIntType getType() { exists(result) } } - // Conversions + /** A `conv.i` instruction. */ class Conv_i extends Conversion, @cil_conv_i { override string getOpcodeName() { result = "conv.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i` instruction. */ class Conv_ovf_i extends Conversion, @cil_conv_ovf_i { override string getOpcodeName() { result = "conv.ovf.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i.un` instruction. */ class Conv_ovf_i_un extends Conversion, @cil_conv_ovf_i_un { override string getOpcodeName() { result = "conv.ovf.i.un" } override UIntType getType() { exists(result) } } + /** A `conv.i1` instruction. */ class Conv_i1 extends Conversion, @cil_conv_i1 { override string getOpcodeName() { result = "conv.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1` instruction. */ class Conv_ovf_i1 extends Conversion, @cil_conv_ovf_i1 { override string getOpcodeName() { result = "conv.ovf.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1.un` instruction. */ class Conv_ovf_i1_un extends Conversion, @cil_conv_ovf_i1_un { override string getOpcodeName() { result = "conv.ovf.i1.un" } override SByteType getType() { exists(result) } } + /** A `conv.i2` instruction. */ class Conv_i2 extends Conversion, @cil_conv_i2 { override string getOpcodeName() { result = "conv.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2` instruction. */ class Conv_ovf_i2 extends Conversion, @cil_conv_ovf_i2 { override string getOpcodeName() { result = "conv.ovf.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2.un` instruction. */ class Conv_ovf_i2_un extends Conversion, @cil_conv_ovf_i2_un { override string getOpcodeName() { result = "conv.ovf.i2.un" } override ShortType getType() { exists(result) } } + /** A `conv.i4` instruction. */ class Conv_i4 extends Conversion, @cil_conv_i4 { override string getOpcodeName() { result = "conv.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4` instruction. */ class Conv_ovf_i4 extends Conversion, @cil_conv_ovf_i4 { override string getOpcodeName() { result = "conv.ovf.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4.un` instruction. */ class Conv_ovf_i4_un extends Conversion, @cil_conv_ovf_i4_un { override string getOpcodeName() { result = "conv.ovf.i4.un" } override IntType getType() { exists(result) } } + /** A `conv.i8` instruction. */ class Conv_i8 extends Conversion, @cil_conv_i8 { override string getOpcodeName() { result = "conv.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8` instruction. */ class Conv_ovf_i8 extends Conversion, @cil_conv_ovf_i8 { override string getOpcodeName() { result = "conv.ovf.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8.un` instruction. */ class Conv_ovf_i8_un extends Conversion, @cil_conv_ovf_i8_un { override string getOpcodeName() { result = "conv.ovf.i8.un" } override LongType getType() { exists(result) } } - // Unsigned conversions + /** A `conv.u` instruction. */ class Conv_u extends Conversion, @cil_conv_u { override string getOpcodeName() { result = "conv.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u` instruction. */ class Conv_ovf_u extends Conversion, @cil_conv_ovf_u { override string getOpcodeName() { result = "conv.ovf.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u.un` instruction. */ class Conv_ovf_u_un extends Conversion, @cil_conv_ovf_u_un { override string getOpcodeName() { result = "conv.ovf.u.un" } override UIntType getType() { exists(result) } } + /** A `conv.u1` instruction. */ class Conv_u1 extends Conversion, @cil_conv_u1 { override string getOpcodeName() { result = "conv.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1` instruction. */ class Conv_ovf_u1 extends Conversion, @cil_conv_ovf_u1 { override string getOpcodeName() { result = "conv.ovf.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1.un` instruction. */ class Conv_ovf_u1_un extends Conversion, @cil_conv_ovf_u1_un { override string getOpcodeName() { result = "conv.ovf.u1.un" } override ByteType getType() { exists(result) } } + /** A `conv.u2` instruction. */ class Conv_u2 extends Conversion, @cil_conv_u2 { override string getOpcodeName() { result = "conv.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2` instruction. */ class Conv_ovf_u2 extends Conversion, @cil_conv_ovf_u2 { override string getOpcodeName() { result = "conv.ovf.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2.un` instruction. */ class Conv_ovf_u2_un extends Conversion, @cil_conv_ovf_u2_un { override string getOpcodeName() { result = "conv.ovf.u2.un" } override UShortType getType() { exists(result) } } + /** A `conv.u4` instruction. */ class Conv_u4 extends Conversion, @cil_conv_u4 { override string getOpcodeName() { result = "conv.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4` instruction. */ class Conv_ovf_u4 extends Conversion, @cil_conv_ovf_u4 { override string getOpcodeName() { result = "conv.ovf.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4.un` instruction. */ class Conv_ovf_u4_un extends Conversion, @cil_conv_ovf_u4_un { override string getOpcodeName() { result = "conv.ovf.u4.un" } override UIntType getType() { exists(result) } } + /** A `conv.u8` instruction. */ class Conv_u8 extends Conversion, @cil_conv_u8 { override string getOpcodeName() { result = "conv.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8` instruction. */ class Conv_ovf_u8 extends Conversion, @cil_conv_ovf_u8 { override string getOpcodeName() { result = "conv.ovf.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8.un` instruction. */ class Conv_ovf_u8_un extends Conversion, @cil_conv_ovf_u8_un { override string getOpcodeName() { result = "conv.ovf.u8.un" } override ULongType getType() { exists(result) } } - // Floating point conversions + /** A `conv.r4` instruction. */ class Conv_r4 extends Conversion, @cil_conv_r4 { override string getOpcodeName() { result = "conv.r4" } override FloatType getType() { exists(result) } } + /** A `conv.r8` instruction. */ class Conv_r8 extends Conversion, @cil_conv_r8 { override string getOpcodeName() { result = "conv.r8" } override DoubleType getType() { exists(result) } } + /** A `conv.r.un` instruction. */ class Conv_r_un extends Conversion, @cil_conv_r_un { override string getOpcodeName() { result = "conv.r.un" } override DoubleType getType() { exists(result) } // ?? } + /** A `volatile.` instruction. */ class Volatile extends Instruction, @cil_volatile { override string getOpcodeName() { result = "volatile." } } - // Indirections + /** An `ldind.i` instruction. */ class Ldind_i extends LoadIndirect, @cil_ldind_i { override string getOpcodeName() { result = "ldind.i" } override IntType getType() { exists(result) } } + /** An `ldind.i1` instruction. */ class Ldind_i1 extends LoadIndirect, @cil_ldind_i1 { override string getOpcodeName() { result = "ldind.i1" } override SByteType getType() { exists(result) } } + /** An `ldind.i2` instruction. */ class Ldind_i2 extends LoadIndirect, @cil_ldind_i2 { override string getOpcodeName() { result = "ldind.i2" } override ShortType getType() { exists(result) } } + /** An `ldind.i4` instruction. */ class Ldind_i4 extends LoadIndirect, @cil_ldind_i4 { override string getOpcodeName() { result = "ldind.i4" } override IntType getType() { exists(result) } } + /** An `ldind.i8` instruction. */ class Ldind_i8 extends LoadIndirect, @cil_ldind_i8 { override string getOpcodeName() { result = "ldind.i8" } override LongType getType() { exists(result) } } + /** An `ldind.r4` instruction. */ class Ldind_r4 extends LoadIndirect, @cil_ldind_r4 { override string getOpcodeName() { result = "ldind.r4" } override FloatType getType() { exists(result) } } + /** An `ldind.r8` instruction. */ class Ldind_r8 extends LoadIndirect, @cil_ldind_r8 { override string getOpcodeName() { result = "ldind.r8" } override DoubleType getType() { exists(result) } } + /** An `ldind.ref` instruction. */ class Ldind_ref extends LoadIndirect, @cil_ldind_ref { override string getOpcodeName() { result = "ldind.ref" } override ObjectType getType() { exists(result) } } + /** An `ldind.u1` instruction. */ class Ldind_u1 extends LoadIndirect, @cil_ldind_u1 { override string getOpcodeName() { result = "ldind.u1" } override ByteType getType() { exists(result) } } + /** An `ldind.u2` instruction. */ class Ldind_u2 extends LoadIndirect, @cil_ldind_u2 { override string getOpcodeName() { result = "ldind.u2" } override UShortType getType() { exists(result) } } + /** An `ldind.u4` instruction. */ class Ldind_u4 extends LoadIndirect, @cil_ldind_u4 { override string getOpcodeName() { result = "ldind.u4" } override UIntType getType() { exists(result) } } + /** An `stind.i` instruction. */ class Stind_i extends StoreIndirect, @cil_stind_i { override string getOpcodeName() { result = "stind.i" } } + /** An `stind.i1` instruction. */ class Stind_i1 extends StoreIndirect, @cil_stind_i1 { override string getOpcodeName() { result = "stind.i1" } } + /** An `stind.i2` instruction. */ class Stind_i2 extends StoreIndirect, @cil_stind_i2 { override string getOpcodeName() { result = "stind.i2" } } + /** An `stind.i4` instruction. */ class Stind_i4 extends StoreIndirect, @cil_stind_i4 { override string getOpcodeName() { result = "stind.i4" } } + /** An `stind.i8` instruction. */ class Stind_i8 extends StoreIndirect, @cil_stind_i8 { override string getOpcodeName() { result = "stind.i8" } } + /** An `stind.r4` instruction. */ class Stind_r4 extends StoreIndirect, @cil_stind_r4 { override string getOpcodeName() { result = "stind.r4" } } + /** An `stind.r8` instruction. */ class Stind_r8 extends StoreIndirect, @cil_stind_r8 { - override string getOpcodeName() { result = "stind.r4" } + override string getOpcodeName() { result = "stind.r8" } } + /** An `stind.ref` instruction. */ class Stind_ref extends StoreIndirect, @cil_stind_ref { override string getOpcodeName() { result = "stind.ref" } } - // Miscellaneous + /** An `stobj` instruction. */ class Stobj extends Instruction, @cil_stobj { override string getOpcodeName() { result = "stobj" } override int getPopCount() { result = 2 } } + /** An `ldftn` instruction. */ class Ldftn extends Expr, @cil_ldftn { override string getOpcodeName() { result = "ldftn" } override int getPopCount() { result = 0 } } + /** An `ldvirtftn` instruction. */ class Ldvirtftn extends Expr, @cil_ldvirtftn { override string getOpcodeName() { result = "ldvirtftn" } override int getPopCount() { result = 1 } } + /** A `sizeof` instruction. */ class Sizeof extends Expr, @cil_sizeof { override string getOpcodeName() { result = "sizeof" } override IntType getType() { exists(result) } } + /** A `localloc` instruction. */ class Localloc extends Expr, @cil_localloc { override string getOpcodeName() { result = "localloc" } @@ -1185,10 +1375,12 @@ module Opcodes { override PointerType getType() { result.getReferentType() instanceof ByteType } } + /** A `readonly.` instruction. */ class Readonly extends Instruction, @cil_readonly { override string getOpcodeName() { result = "readonly." } } + /** A `mkrefany` instruction. */ class Mkrefany extends Expr, @cil_mkrefany { override string getOpcodeName() { result = "mkrefany" } @@ -1197,6 +1389,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** A `refanytype` instruction. */ class Refanytype extends Expr, @cil_refanytype { override string getOpcodeName() { result = "refanytype" } @@ -1205,6 +1398,7 @@ module Opcodes { override SystemType getType() { exists(result) } } + /** An `arglist` instruction. */ class Arglist extends Expr, @cil_arglist { override string getOpcodeName() { result = "arglist" } } diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 3dbcd7cbdc3..42ae43c3748 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -29,8 +29,10 @@ class Assignable extends Declaration, @assignable { * An assignable that is also a member. Either a field (`Field`), a * property (`Property`), an indexer (`Indexer`), or an event (`Event`). */ -class AssignableMember extends Member, Assignable { +class AssignableMember extends Member, Assignable, Attributable { override AssignableMemberAccess getAnAccess() { result = Assignable.super.getAnAccess() } + + override string toString() { result = Assignable.super.toString() } } /** @@ -55,7 +57,7 @@ private predicate nameOfChild(NameOfExpr noe, Expr child) { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -89,7 +91,7 @@ class AssignableRead extends AssignableAccess { * that can be reached from this read without passing through any other reads, * and which is guaranteed to read the same value. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -131,7 +133,7 @@ class AssignableRead extends AssignableAccess { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -454,7 +456,7 @@ class AssignableDefinition extends TAssignableDefinition { * reads, and which is guaranteed to read the value assigned in this * definition. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -720,7 +722,7 @@ module AssignableDefinitions { * An initializer definition for a field or a property, for example * line 2 in * - * ``` + * ```csharp * class C { * int Field = 0; * } diff --git a/csharp/ql/src/semmle/code/csharp/Attribute.qll b/csharp/ql/src/semmle/code/csharp/Attribute.qll index a7d7729903a..fd19423441e 100644 --- a/csharp/ql/src/semmle/code/csharp/Attribute.qll +++ b/csharp/ql/src/semmle/code/csharp/Attribute.qll @@ -38,7 +38,7 @@ class Attributable extends @attributable { /** * An attribute, for example `[...]` on line 1 in * - * ``` + * ```csharp * [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] * public static extern int GetFinalPathNameByHandle( * SafeHandle handle, @@ -64,7 +64,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the `i`th constructor argument of this attribute. For example, only * `true` is a constructor argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ @@ -76,7 +76,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the named argument `name` of this attribute. For example, only * `0` is a named argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index 4443ec9bc7c..9f6e2698f42 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -58,7 +58,7 @@ module Stages { cached private predicate forceCachingInSameStageRev() { - localAdditionalTaintStep(_, _) + defaultAdditionalTaintStep(_, _) or any(ArgumentNode n).argumentOf(_, _) or @@ -68,7 +68,7 @@ module Stages { or exists(any(DataFlow::Node n).getType()) or - exists(any(DataFlow::Node n).getTypeBound()) + exists(any(NodeImpl n).getDataFlowType()) or exists(any(DataFlow::Node n).getLocation()) or diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index f3ef15d59f7..4e0ee381dbe 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -25,12 +25,6 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal /** Gets the annotated return type of this callable. */ final AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } - /** DEPRECATED: Use `getAnnotatedReturnType().isRef()` instead. */ - deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() } - - /** DEPRECATED: Use `getAnnotatedReturnType().isReadonlyRef()` instead. */ - deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() } - override Callable getSourceDeclaration() { result = Parameterizable.super.getSourceDeclaration() } /** @@ -50,7 +44,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * where the same callable is compiled multiple times. For example, if we * compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -60,7 +54,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 1; } @@ -98,7 +92,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * the case where the same callable is compiled multiple times. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 0; } @@ -108,7 +102,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 1; } @@ -134,7 +128,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * the case where the same callable is compiled multiple times. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -144,7 +138,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 1; @@ -229,7 +223,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal /** * A method, for example * - * ``` + * ```csharp * public override bool Equals(object other) { * ... * } @@ -295,7 +289,7 @@ class Method extends Callable, Virtualizable, Attributable, @method { /** * An extension method, for example * - * ``` + * ```csharp * static bool IsDefined(this Widget w) { * ... * } @@ -313,7 +307,7 @@ class ExtensionMethod extends Method { /** * A constructor, for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -332,7 +326,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * the initializer of the constructor on line 2 is `this(null)` * on line 3 in * - * ``` + * ```csharp * class C { * public C() * : this(null) { ... } @@ -367,7 +361,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * A static constructor (as opposed to an instance constructor), * for example `static public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * static public C() { } * } @@ -383,7 +377,7 @@ class StaticConstructor extends Constructor { * An instance constructor (as opposed to a static constructor), * for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -396,7 +390,7 @@ class InstanceConstructor extends Constructor { /** * A destructor, for example `~C() { }` on line 2 in * - * ``` + * ```csharp * class C { * ~C() { } * } @@ -467,7 +461,7 @@ class UnaryOperator extends Operator { /** * A user-defined plus operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget w) { * ... * } @@ -482,7 +476,7 @@ class PlusOperator extends UnaryOperator { /** * A user-defined minus operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget w) { * ... * } @@ -497,7 +491,7 @@ class MinusOperator extends UnaryOperator { /** * A user-defined not operator (`!`), for example * - * ``` + * ```csharp * public static bool operator !(Widget w) { * ... * } @@ -512,7 +506,7 @@ class NotOperator extends UnaryOperator { /** * A user-defined complement operator (`~`), for example * - * ``` + * ```csharp * public static Widget operator ~(Widget w) { * ... * } @@ -527,7 +521,7 @@ class ComplementOperator extends UnaryOperator { /** * A user-defined increment operator (`++`), for example * - * ``` + * ```csharp * public static Widget operator ++(Widget w) { * ... * } @@ -542,7 +536,7 @@ class IncrementOperator extends UnaryOperator { /** * A user-defined decrement operator (`--`), for example * - * ``` + * ```csharp * public static Widget operator --(Widget w) { * ... * } @@ -557,7 +551,7 @@ class DecrementOperator extends UnaryOperator { /** * A user-defined false operator (`false`), for example * - * ``` + * ```csharp * public static bool operator false(Widget w) { * ... * } @@ -572,7 +566,7 @@ class FalseOperator extends UnaryOperator { /** * A user-defined true operator (`true`), for example * - * ``` + * ```csharp * public static bool operator true(Widget w) { * ... * } @@ -604,7 +598,7 @@ class BinaryOperator extends Operator { /** * A user-defined addition operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget lhs, Widget rhs) { * ... * } @@ -619,7 +613,7 @@ class AddOperator extends BinaryOperator { /** * A user-defined subtraction operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget lhs, Widget rhs) { * ... * } @@ -634,7 +628,7 @@ class SubOperator extends BinaryOperator { /** * A user-defined multiplication operator (`*`), for example * - * ``` + * ```csharp * public static Widget operator *(Widget lhs, Widget rhs) { * ... * } @@ -649,7 +643,7 @@ class MulOperator extends BinaryOperator { /** * A user-defined division operator (`/`), for example * - * ``` + * ```csharp * public static Widget operator /(Widget lhs, Widget rhs) { * ... * } @@ -664,7 +658,7 @@ class DivOperator extends BinaryOperator { /** * A user-defined remainder operator (`%`), for example * - * ``` + * ```csharp * public static Widget operator %(Widget lhs, Widget rhs) { * ... * } @@ -679,7 +673,7 @@ class RemOperator extends BinaryOperator { /** * A user-defined and operator (`&`), for example * - * ``` + * ```csharp * public static Widget operator &(Widget lhs, Widget rhs) { * ... * } @@ -694,7 +688,7 @@ class AndOperator extends BinaryOperator { /** * A user-defined or operator (`|`), for example * - * ``` + * ```csharp * public static Widget operator |(Widget lhs, Widget rhs) { * ... * } @@ -709,7 +703,7 @@ class OrOperator extends BinaryOperator { /** * A user-defined xor operator (`^`), for example * - * ``` + * ```csharp * public static Widget operator ^(Widget lhs, Widget rhs) { * ... * } @@ -724,7 +718,7 @@ class XorOperator extends BinaryOperator { /** * A user-defined left shift operator (`<<`), for example * - * ``` + * ```csharp * public static Widget operator <<(Widget lhs, Widget rhs) { * ... * } @@ -739,7 +733,7 @@ class LShiftOperator extends BinaryOperator { /** * A user-defined right shift operator (`>>`), for example * - * ``` + * ```csharp * public static Widget operator >>(Widget lhs, Widget rhs) { * ... * } @@ -754,7 +748,7 @@ class RShiftOperator extends BinaryOperator { /** * A user-defined equals operator (`==`), for example * - * ``` + * ```csharp * public static bool operator ==(Widget lhs, Widget rhs) { * ... * } @@ -769,7 +763,7 @@ class EQOperator extends BinaryOperator { /** * A user-defined not equals operator (`!=`), for example * - * ``` + * ```csharp * public static bool operator !=(Widget lhs, Widget rhs) { * ... * } @@ -784,7 +778,7 @@ class NEOperator extends BinaryOperator { /** * A user-defined lesser than operator (`<`), for example * - * ``` + * ```csharp * public static bool operator <(Widget lhs, Widget rhs) { * ... * } @@ -799,7 +793,7 @@ class LTOperator extends BinaryOperator { /** * A user-defined greater than operator (`>`), for example * - * ``` + * ```csharp * public static bool operator >(Widget lhs, Widget rhs) { * ... * } @@ -814,7 +808,7 @@ class GTOperator extends BinaryOperator { /** * A user-defined less than or equals operator (`<=`), for example * - * ``` + * ```csharp * public static bool operator <=(Widget lhs, Widget rhs) { * ... * } @@ -829,7 +823,7 @@ class LEOperator extends BinaryOperator { /** * A user-defined greater than or equals operator (`>=`), for example * - * ``` + * ```csharp * public static bool operator >=(Widget lhs, Widget rhs) { * ... * } @@ -844,7 +838,7 @@ class GEOperator extends BinaryOperator { /** * A user-defined conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -866,7 +860,7 @@ class ConversionOperator extends Operator { /** * A user-defined implicit conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -881,7 +875,7 @@ class ImplicitConversionOperator extends ConversionOperator { /** * A user-defined explicit conversion operator, for example * - * ``` + * ```csharp * public static explicit operator int(BigInteger i) { * ... * } @@ -897,7 +891,7 @@ class ExplicitConversionOperator extends ConversionOperator { * A local function, defined within the scope of another callable. * For example, `Fac` on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/Comments.qll b/csharp/ql/src/semmle/code/csharp/Comments.qll index 1e81fb1fc1c..41f4e5b0be8 100644 --- a/csharp/ql/src/semmle/code/csharp/Comments.qll +++ b/csharp/ql/src/semmle/code/csharp/Comments.qll @@ -34,7 +34,7 @@ class CommentLine extends @commentline { /** * A single-line comment, for example line 1 in * - * ``` + * ```csharp * // This method returns the successor of its argument * public int Succ(int x) => x + 1; * ``` @@ -47,7 +47,7 @@ class SinglelineComment extends CommentLine, @singlelinecomment { * A line of comment in a multiline style, for example each of the * lines in * - * ``` + * ```csharp * /* This is * a comment * / * ``` @@ -60,7 +60,7 @@ class MultilineComment extends CommentLine, @multilinecomment { * A line of XML documentation comment, for example each of the * lines in * - * ``` + * ```csharp * /// * /// This method ... * /// @@ -148,7 +148,7 @@ class XmlComment extends CommentLine, @xmldoccomment { /** * A collection of adjacent comment lines, for example * - * ``` + * ```csharp * /// * /// Represents a named tuple. * /// diff --git a/csharp/ql/src/semmle/code/csharp/Conversion.qll b/csharp/ql/src/semmle/code/csharp/Conversion.qll index 1bfc1eb8f61..60abdfbebed 100644 --- a/csharp/ql/src/semmle/code/csharp/Conversion.qll +++ b/csharp/ql/src/semmle/code/csharp/Conversion.qll @@ -362,7 +362,7 @@ private module Identity { IdentityConvertibleGenericType fromType, IdentityConvertibleGenericType toType ) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | @@ -773,7 +773,7 @@ predicate convConversionOperator(Type fromType, Type toType) { /** 13.1.3.2: Variance conversion. */ private predicate convVariance(GenericType fromType, GenericType toType) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | diff --git a/csharp/ql/src/semmle/code/csharp/Event.qll b/csharp/ql/src/semmle/code/csharp/Event.qll index 38f89428b6f..6b4ecc39190 100644 --- a/csharp/ql/src/semmle/code/csharp/Event.qll +++ b/csharp/ql/src/semmle/code/csharp/Event.qll @@ -8,7 +8,7 @@ import Type /** * An event, for example `E` on line 3 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E; @@ -67,7 +67,7 @@ class Event extends DeclarationWithAccessors, @event { * An event accessor, for example `add` on line 4 or `remove` * on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -95,7 +95,7 @@ class EventAccessor extends Accessor, @event_accessor { /** * An add event accessor, for example `add` on line 4 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -112,7 +112,7 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor { /** * A remove event accessor, for example `remove` on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 0cceb3cb8c2..93fbe1d579c 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -126,7 +126,7 @@ class TopLevelExprParent extends Element, @top_level_expr_parent { * encountered multiple potential implementations at compile-time. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -136,7 +136,7 @@ class TopLevelExprParent extends Element, @top_level_expr_parent { * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 1; diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 79481a8c63d..9efdb46b867 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -23,19 +23,19 @@ private import dotnet */ class Generic extends DotNet::Generic, Declaration, @generic { Generic() { - is_generic(this) or - is_constructed(this) + type_parameters(_, _, this, _) or + type_arguments(_, _, this) } } /** - * A generic declaration that can have type parameters. + * A generic declaration with type parameters. * * Either an unbound generic type (`UnboundGenericType`) or an unbound generic method * (`UnboundGenericMethod`). */ class UnboundGeneric extends DotNet::UnboundGeneric, Generic { - UnboundGeneric() { is_generic(this) } + UnboundGeneric() { type_parameters(_, _, this, _) } override TypeParameter getTypeParameter(int n) { type_parameters(result, n, this, _) } @@ -47,13 +47,13 @@ class UnboundGeneric extends DotNet::UnboundGeneric, Generic { } /** - * A declaration constructed from an `UnboundGeneric` by supplying type arguments. + * A constructed generic. * * Either a constructed generic type (`ConstructedType`) or a constructed * generic method (`ConstructedMethod`). */ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { - ConstructedGeneric() { is_constructed(this) } + ConstructedGeneric() { type_arguments(_, _, this) } override UnboundGeneric getUnboundGeneric() { constructed_generic(this, result) } @@ -61,10 +61,7 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { result = getUnboundGeneric().getSourceDeclaration() } - override int getNumberOfTypeArguments() { - // getTypeArgument() could fail if the type does not exist in the database - result = count(int i | type_arguments(_, i, this)) - } + override int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, this)) } override Type getTypeArgument(int i) { none() } @@ -84,11 +81,12 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { */ class UnboundGenericType extends ValueOrRefType, UnboundGeneric { /** - * Gets a bound/constructed version of this unbound generic type. This includes not only closed constructed types such as `G`, - * but also open constructed types such as the `G` in `class Other { G g; }`. Note that such a type is distinct from the - * `G` used in the class definition, since in `G g;` the `T` will be the actual type parameter used for the `Other` that contains - * `g`, whereas in `class G { ... }` the `T` is a formal type parameter of `G`. It is important not to get confused by the superficial - * syntactic similarity. + * Gets a bound/constructed version of this unbound generic type. This includes + * not only closed constructed types such as `G`, but also open constructed + * types such as the `G` in `class Other { G g; }`. Note that such a type + * is distinct from the `G` used in the class definition, since in `G g;` + * the `T` will be the actual type parameter used for the `Other` that contains + * `g`, whereas in `class G { ... }` the `T` is a formal type parameter of `G`. */ override ConstructedType getAConstructedGeneric() { result = UnboundGeneric.super.getAConstructedGeneric() @@ -192,31 +190,13 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { * * For example, `where` on line 2 in * - * ``` + * ```csharp * class Factory * where T : ICloneable { * } * ``` */ class TypeParameterConstraints extends Element, @type_parameter_constraints { - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets a specific interface constraint, if any. - */ - deprecated Interface getAnInterfaceConstraint() { result = getATypeConstraint() } - - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets a specific type parameter constraint, if any. - */ - deprecated TypeParameter getATypeParameterConstraint() { result = getATypeConstraint() } - - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets the specific class constraint, if any. - */ - deprecated Class getClassConstraint() { result = getATypeConstraint() } - /** Gets a specific type constraint, if any. */ Type getATypeConstraint() { specific_type_parameter_constraints(this, getTypeRef(result)) } @@ -253,7 +233,7 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints { * * For example, * - * ``` + * ```csharp * struct KeyValuePair { * ... * } @@ -276,7 +256,7 @@ class UnboundGenericStruct extends Struct, UnboundGenericType { /** * An unbound generic class, for example * - * ``` + * ```csharp * class List { * ... * } @@ -299,7 +279,7 @@ class UnboundGenericClass extends Class, UnboundGenericType { /** * An unbound generic interface, for example * - * ``` + * ```csharp * interface IEnumerable { * ... * } @@ -325,7 +305,7 @@ class UnboundGenericInterface extends Interface, UnboundGenericType { * * For example * - * ``` + * ```csharp * delegate void F(T t); * ``` */ @@ -350,15 +330,16 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType { } /** - * A constructed (bound) type. This is a generic type for which actual type arguments have been supplied, - * for example `G` or the `G` in `class Other { G g; }`. Constructed types can be divided further into - * those that are open (for example `G1` or `G2`), in the sense that one or more of their type arguments - * is a type parameter, versus those that are closed (for example `G1` or `G2`). We do not - * currently distinguish the two in this library. + * A constructed (bound) type. This is a generic type for which actual type + * arguments have been supplied, for example `G` or the `G` in + * `class Other { G g; }`. Constructed types can be divided further into + * those that are open (for example `G1` or `G2`), in the sense + * that one or more of their type arguments is a type parameter, versus those + * that are closed (for example `G1` or `G2`). * - * Either a constructed `struct` (`ConstructedStruct`), constructed `class` (`ConstructedClass`), - * constructed `interface` (`ConstructedInterface`), or constructed method - * (`ConstructedMethod`). + * Either a constructed `struct` (`ConstructedStruct`), constructed `class` + * (`ConstructedClass`), constructed `interface` (`ConstructedInterface`), + * or constructed method (`ConstructedMethod`). */ class ConstructedType extends ValueOrRefType, ConstructedGeneric { override UnboundGenericType getSourceDeclaration() { @@ -394,7 +375,7 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { * * For example, `KeyValuePair` on line 4 in * - * ``` + * ```csharp * struct KeyValuePair { ... } * * class C { @@ -417,7 +398,7 @@ class ConstructedStruct extends Struct, ConstructedType { * * For example, `List` on line 4 in * - * ``` + * ```csharp * class List { ... } * * class C { @@ -440,7 +421,7 @@ class ConstructedClass extends Class, ConstructedType { * * For example, `IEnumerable` on line 4 in * - * ``` + * ```csharp * interface IEnumerable { ... } * * class C { @@ -463,7 +444,7 @@ class ConstructedInterface extends Interface, ConstructedType { * * For example, `F` on line 4 in * - * ``` + * ```csharp * delegate void F(T t); * * class C { @@ -485,7 +466,7 @@ class ConstructedDelegateType extends DelegateType, ConstructedType { * An unbound generic method. This is a generic method whose signature involves formal type parameters, * For example `M` on line 2 in * - * ``` + * ```csharp * class C { * void M() { ... } * } @@ -511,7 +492,7 @@ class UnboundGenericMethod extends Method, UnboundGeneric { * A constructed (bound) method, for example the target `M` of the call on * line 5 in * - * ``` + * ```csharp * class C { * void M() { ... } * @@ -545,8 +526,8 @@ class ConstructedMethod extends Method, ConstructedGeneric { /** * An unbound generic local function, for example `f` on line 3 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f(T t) { ... } * } @@ -563,8 +544,8 @@ class UnboundLocalFunction extends LocalFunction, UnboundGeneric { * A constructed generic local function, for example the target `f` * of the function call `f(5)` on line 4 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f(T t) { ... } * f(5); @@ -599,7 +580,7 @@ class NonConstructedMethod extends Method { * * Example: * - * ``` + * ```csharp * class A { * void M1(T1 x1) { } * void M2(T1 x1, T2 x) { } diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index 6e523e1ea30..5ea4b51bfa2 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -21,7 +21,7 @@ private import Conversion * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -52,7 +52,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -143,10 +143,10 @@ private predicate getACompatibleInterfaceAccessorAux( * of the interface `i`. Note that the class or struct need not be a * sub type of the interface in the inheritance hierarchy: * - * ``` - * interface I { void M() } + * ```csharp + * interface I { void M(); } * - * class A { public void M() } + * class A { public void M() { } } * * class B { } * @@ -250,7 +250,7 @@ private module Gvn { private class LeafType extends Type { LeafType() { - not exists(this.getAChild()) and + not this instanceof Unification::GenericType and not this instanceof MethodTypeParameter and not this instanceof DynamicType } @@ -267,7 +267,9 @@ private module Gvn { gvnConstructedCons(_, _, _, head, tail) } - private ConstructedGvnTypeList gvnConstructed(Type t, Unification::CompoundTypeKind k, int i) { + private ConstructedGvnTypeList gvnConstructed( + Unification::GenericType t, Unification::CompoundTypeKind k, int i + ) { result = TConstructedGvnTypeNil(k) and i = -1 and k = Unification::getTypeKind(t) @@ -278,14 +280,17 @@ private module Gvn { } pragma[noinline] - private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) } + private GvnType gvnTypeArgument(Unification::GenericType t, int i) { + result = getGlobalValueNumber(t.getArgument(i)) + } pragma[noinline] private predicate gvnConstructedCons( - Type t, Unification::CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail + Unification::GenericType t, Unification::CompoundTypeKind k, int i, GvnType head, + ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChild(t, i) + head = gvnTypeArgument(t, i) } /** Gets the global value number for a given type. */ @@ -319,6 +324,8 @@ private module Gvn { } private class ConstructedGvnTypeList extends TConstructedGvnTypeList { + Unification::CompoundTypeKind getKind() { this = gvnConstructed(_, result, _) } + private int length() { this = TConstructedGvnTypeNil(_) and result = -1 or @@ -338,17 +345,47 @@ private module Gvn { ) } + /** + * Gets a textual representation of this constructed type, restricted + * to the prefix `t` of the underlying source declaration type. + * + * The `toString()` calculation needs to be split up into prefixes, in + * order to apply the type arguments correctly. For example, a source + * declaration type `A<>.B.C<,>` applied to types `int, string, bool` + * needs to be printed as `A.B.C`. + */ + language[monotonicAggregates] + private string toStringConstructed(Unification::GenericType t) { + t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and + exists(int offset, int children, string name, string nameArgs | + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = Unification::getNameNested(t) and + if children = 0 + then nameArgs = name + else + exists(string offsetArgs | + offsetArgs = + concat(int i | + i in [offset .. offset + children - 1] + | + this.getArg(i).toString(), "," order by i + ) and + nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + ) + | + offset = 0 and result = nameArgs + or + result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs + ) + } + language[monotonicAggregates] string toString() { - exists(Unification::CompoundTypeKind k, string args | - this = gvnConstructed(_, k, _) and - args = - concat(int i | - i in [0 .. k.getNumberOfTypeParameters() - 1] - | - this.getArg(i).toString(), "," order by i - ) and - result = k.toString(args) + exists(Unification::CompoundTypeKind k | k = this.getKind() | + result = k.toStringBuiltin(this.getArg(0).toString()) + or + result = this.toStringConstructed(k.getConstructedSourceDeclaration()) ) } diff --git a/csharp/ql/src/semmle/code/csharp/Location.qll b/csharp/ql/src/semmle/code/csharp/Location.qll index 178eddc1d4d..99df294ae63 100644 --- a/csharp/ql/src/semmle/code/csharp/Location.qll +++ b/csharp/ql/src/semmle/code/csharp/Location.qll @@ -38,16 +38,16 @@ class Location extends @location { /** Gets a textual representation of this location. */ string toString() { none() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ final int getStartLine() { this.hasLocationInfo(_, result, _, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ final int getEndLine() { this.hasLocationInfo(_, _, _, result, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ final int getStartColumn() { this.hasLocationInfo(_, _, result, _, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ final int getEndColumn() { this.hasLocationInfo(_, _, _, _, result) } } diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll index dd2a64c47ae..6f29ee5924a 100644 --- a/csharp/ql/src/semmle/code/csharp/Member.qll +++ b/csharp/ql/src/semmle/code/csharp/Member.qll @@ -24,7 +24,7 @@ class Declaration extends DotNet::Declaration, Element, @declaration { * Gets the fully qualified name of this declaration, including types, for example * the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } @@ -195,7 +195,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -223,7 +223,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -251,7 +251,7 @@ class Virtualizable extends Member, @virtualizable { * Note that this is generally *not* equivalent with * `getOverridee*().getImplementee()`, as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } diff --git a/csharp/ql/src/semmle/code/csharp/Namespace.qll b/csharp/ql/src/semmle/code/csharp/Namespace.qll index 0c94d182bee..c686d61a5a5 100644 --- a/csharp/ql/src/semmle/code/csharp/Namespace.qll +++ b/csharp/ql/src/semmle/code/csharp/Namespace.qll @@ -12,7 +12,7 @@ class TypeContainer extends DotNet::NamedElement, Element, @type_container { } /** * A namespace, for example * - * ``` + * ```csharp * namespace System.IO { * ... * } @@ -37,7 +37,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a type directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -49,7 +49,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a class directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -61,7 +61,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an interface directly declared in this namespace, if any. * For example, the interface `IEnumerable` in * - * ``` + * ```csharp * namespace System.Collections { * public interface IEnumerable { ... } * } @@ -73,7 +73,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a struct directly declared in this namespace, if any. * For example, the struct `Timespan` in * - * ``` + * ```csharp * namespace System { * public struct Timespan { ... } * } @@ -85,7 +85,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an enum directly declared in this namespace, if any. * For example, the enum `DayOfWeek` in * - * ``` + * ```csharp * namespace System { * public enum DayOfWeek { ... } * } @@ -97,7 +97,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a delegate directly declared in this namespace, if any. * For example, the delegate `AsyncCallback` in * - * ``` + * ```csharp * namespace System { * public delegate void AsyncCallback(IAsyncResult ar); * } @@ -135,7 +135,7 @@ class GlobalNamespace extends Namespace { /** * An explicit namespace declaration in a source file. For example: * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -145,7 +145,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { /** * Gets the declared namespace, for example `N1.N2` in * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -159,7 +159,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * declaration `namespace N1` on line 1, but `namespace N1` on line 1 and * `namespace N1.N2` on line 7 do not have parent namespace declarations. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -180,7 +180,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * `namespace N2` on line 2 is a child namespace declaration of * `namespace N1` on line 1. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -196,7 +196,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * Gets a type directly declared within this namespace declaration. * For example, class `C` in * - * ``` + * ```csharp * namespace N { * class C { ... } * } diff --git a/csharp/ql/src/semmle/code/csharp/Property.qll b/csharp/ql/src/semmle/code/csharp/Property.qll index d7013927846..d71a1034226 100644 --- a/csharp/ql/src/semmle/code/csharp/Property.qll +++ b/csharp/ql/src/semmle/code/csharp/Property.qll @@ -106,7 +106,7 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE /** * A property, for example `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { get; set; } * } @@ -123,7 +123,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property is automatically implemented. For example, `P1` * on line 2 is automatically implemented, while `P2` on line 5 is not in * - * ``` + * ```csharp * class C { * public int P1 { get; set; } * @@ -195,7 +195,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the initial value of this property, if any. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -207,7 +207,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property has an initial value. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -219,7 +219,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the expression body of this property, if any. For example, the expression * body of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P => 20; * } @@ -237,7 +237,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper /** * An indexer, for example `string this[int i]` on line 2 in * - * ``` + * ```csharp * class C { * public string this[int i] { * get { return i.ToString(); } @@ -261,7 +261,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer * Gets the expression body of this indexer, if any. For example, the * expression body of the indexer on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int this[int i] => 20; * } @@ -314,7 +314,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * Gets the declaration that this accessor belongs to. For example, both * accessors on lines 3 and 4 belong to the property `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -330,7 +330,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * the `get` accessor on line 3 has no access modifier and the `set` accessor * on line 4 has a `private` access modifier in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -349,7 +349,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * has the modifiers `public` and `virtual`, and the `set` accessor on line 4 * has the modifiers `private` and `virtual` in * - * ``` + * ```csharp * class C { * public virtual int P { * get; @@ -375,7 +375,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { /** * A `get` accessor, for example `get { return p; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -394,7 +394,7 @@ class Getter extends Accessor, @getter { * Gets the field used in the trival implementation of this getter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -420,7 +420,7 @@ class Getter extends Accessor, @getter { /** * A `set` accessor, for example `set { p = value; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -442,7 +442,7 @@ class Setter extends Accessor, @setter { * Gets the field used in the trival implementation of this setter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -478,7 +478,7 @@ private ParameterAccess accessToValue() { * A property with a trivial getter and setter. For example, properties `P1` * and `P2` are trivial, while `P3` is not, in * - * ``` + * ```csharp * public class C { * int p1; * public int P1 { @@ -536,7 +536,7 @@ class IndexerProperty extends Property { // too many indexer calls, for example the call to the indexer // setter at `dict[0]` in // - // ``` + // ```csharp // class A // { // Dictionary dict; diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 710a4ac8f95..d020e9afebf 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -44,7 +44,7 @@ class Stmt extends ControlFlowElement, @stmt { /** * A block statement, for example * - * ``` + * ```csharp * { * ... * } @@ -81,7 +81,7 @@ class BlockStmt extends Stmt, @block_stmt { /** * An expression statement, for example `M1()` on line 5 * - * ``` + * ```csharp * class C { * int M1() { ... } * @@ -111,7 +111,7 @@ class SelectionStmt extends Stmt, @cond_stmt { /** * An `if` statement, for example * - * ``` + * ```csharp * if (x==0) { * ... * } else { @@ -136,7 +136,7 @@ class IfStmt extends SelectionStmt, @if_stmt { /** * A `switch` statement, for example * - * ``` + * ```csharp * switch (instruction) { * ... * } @@ -152,7 +152,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -178,9 +178,6 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { /** Gets the default case of this `switch` statement, if any. */ DefaultCase getDefaultCase() { result = this.getACase() } - /** Gets a type case of this `switch` statement, if any. */ - deprecated TypeCase getATypeCase() { result = this.getACase() } - override string toString() { result = "switch (...) {...}" } /** @@ -188,7 +185,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -271,7 +268,7 @@ class CaseStmt extends Case, @case_stmt { * Gets the condition on this case, if any. For example, the type case on line 3 * has no condition, and the type case on line 4 has condition `s.Length > 0`, in * - * ``` + * ```csharp * switch(p) * { * case int i: @@ -293,7 +290,7 @@ class CaseStmt extends Case, @case_stmt { * A constant case of a `switch` statement, for example `case OpCode.Nop:` * on line 2 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -310,78 +307,11 @@ class ConstCase extends CaseStmt, LabeledStmt { override string toString() { result = CaseStmt.super.toString() } } -/** - * A type matching case in a `switch` statement, for example `case int i:` on line 3 or - * `case string s when s.Length > 0:` on line 4 in - * - * ``` - * switch(p) - * { - * case int i: - * case string s when s.Length > 0: - * break; - * ... - * } - * ``` - */ -deprecated class TypeCase extends CaseStmt { - private TypeAccess ta; - - TypeCase() { expr_parent(ta, 1, this) } - - /** - * Gets the local variable declaration of this type case, if any. For example, - * the local variable declaration of the type case on line 3 is `string s` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * case bool _: - * break; - * ... - * } - * ``` - */ - LocalVariableDeclExpr getVariableDeclExpr() { result = this.getPattern() } - - /** - * Gets the type access of this case, for example access to `string` or - * access to `int` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * ... - * } - * ``` - */ - TypeAccess getTypeAccess() { result = ta } - - /** - * Gets the type being checked by this case. For example, the type being checked - * by the type case on line 3 is `string` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * ... - * } - * ``` - */ - Type getCheckedType() { result = this.getTypeAccess().getType() } -} - /** * A default case of a `switch` statement, for example `default:` on * line 3 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -414,7 +344,7 @@ class LoopStmt extends Stmt, @loop_stmt { /** * A `while` statement, for example * - * ``` + * ```csharp * while (remaining > 0) { * ... * } @@ -429,7 +359,7 @@ class WhileStmt extends LoopStmt, @while_stmt { /** * A `do`-`while` statement, for example * - * ``` + * ```csharp * do { * ... * } @@ -445,7 +375,7 @@ class DoStmt extends LoopStmt, @do_stmt { /** * A `for` loop, for example * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -457,7 +387,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i = 0` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -471,7 +401,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) initializer is `j = 10` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++) { * ... * } @@ -488,7 +418,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i++` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -501,7 +431,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) update expression is `j--` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++, j--) { * ... * } @@ -515,7 +445,7 @@ class ForStmt extends LoopStmt, @for_stmt { /** * A `foreach` loop, for example * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -527,7 +457,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -540,7 +470,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `var item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -553,7 +483,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` is the 0th local variable declaration in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -569,7 +499,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * Gets the local variable declaration tuple of this `foreach` loop, if any. * For example, `(int a, int b)` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -582,7 +512,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` is the 0th local variable in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -595,7 +525,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` and `b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -608,7 +538,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` and `int b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -623,7 +553,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `items` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -646,7 +576,7 @@ class JumpStmt extends Stmt, @jump_stmt { } /** * A `break` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -661,7 +591,7 @@ class BreakStmt extends JumpStmt, @break_stmt { /** * A `continue` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (!done) @@ -688,7 +618,7 @@ class GotoStmt extends JumpStmt, @goto_any_stmt { /** * A `goto` statement that jumps to a labeled statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -714,7 +644,7 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -739,7 +669,7 @@ class GotoCaseStmt extends GotoStmt, @goto_case_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -759,7 +689,7 @@ class GotoDefaultStmt extends GotoStmt, @goto_default_stmt { /** * A `throw` statement, for example line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -797,7 +727,7 @@ class ExceptionClass extends Class { /** * A `return` statement, for example line 2 in * - * ``` + * ```csharp * int M() { * return 0; * } @@ -824,7 +754,7 @@ class YieldStmt extends JumpStmt, @yield_stmt { /** * A `yield break` statement, for example line 6 in * - * ``` + * ```csharp * IEnumerable DownFrom(int i) { * while (true) { * if (i > 0) @@ -844,7 +774,7 @@ class YieldBreakStmt extends YieldStmt { /** * A `yield return` statement, for example line 4 in * - * ``` + * ```csharp * IEnumerable DownFrom(int i) { * while (true) { * if (i > 0) @@ -864,7 +794,7 @@ class YieldReturnStmt extends YieldStmt { /** * A `try` statement, for example * - * ``` + * ```csharp * try { * ... * } @@ -970,7 +900,7 @@ class CatchClause extends Stmt, @catch { * Gets the type of the exception caught. For example, the type of the exception * caught on line 4 is `System.IO.IOException` in * - * ``` + * ```csharp * try { * ... * } @@ -985,7 +915,7 @@ class CatchClause extends Stmt, @catch { * Gets the `catch` filter clause, if any. For example, the filter expression * of the catch clause on line 4 is `ex.HResult == 1` in * - * ``` + * ```csharp * try { * ... * } @@ -1014,7 +944,7 @@ class CatchClause extends Stmt, @catch { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -1042,7 +972,7 @@ class SpecificCatchClause extends CatchClause { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -1060,7 +990,7 @@ class GeneralCatchClause extends CatchClause { /** * A `checked` statement, for example * - * ``` + * ```csharp * checked { * int i = 2147483647; * i++; @@ -1077,7 +1007,7 @@ class CheckedStmt extends Stmt, @checked_stmt { /** * An `unchecked` statement, for example * - * ``` + * ```csharp * unchecked { * int i = 2147483647; * i++; @@ -1094,7 +1024,7 @@ class UncheckedStmt extends Stmt, @unchecked_stmt { /** * A `lock` statement, for example * - * ``` + * ```csharp * lock (mutex) { * ... * } @@ -1144,7 +1074,7 @@ class UsingStmt extends Stmt, @using_stmt { * expression assigned to a variable, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1153,39 +1083,19 @@ class UsingStmt extends Stmt, @using_stmt { * or an expression directly used, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (File.Open("settings.xml")) { * ... * } * ``` */ Expr getAnExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getExpr() instead. - * Gets the expression directly used by this `using` statement, if any. For - * example, `f` on line 2 in - * - * ``` - * var f = File.Open("settings.xml"); - * using (f) { - * ... - * } - * ``` - */ - deprecated Expr getExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getBody() instead. - * Gets the body of this `using` statement. - */ - deprecated Stmt getBody() { none() } } /** * A `using` block statement, for example * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1205,14 +1115,14 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * Gets the expression directly used by this `using` statement, if any. For * example, `f` on line 2 in * - * ``` + * ```csharp * var f = File.Open("settings.xml"); * using (f) { * ... * } * ``` */ - override Expr getExpr() { result = this.getChild(0) } + Expr getExpr() { result = this.getChild(0) } override Expr getAnExpr() { result = this.getAVariableDeclExpr().getInitializer() @@ -1221,7 +1131,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { } /** Gets the body of this `using` statement. */ - override Stmt getBody() { result.getParent() = this } + Stmt getBody() { result.getParent() = this } override string toString() { result = "using (...) {...}" } } @@ -1229,7 +1139,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { /** * A local declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1240,7 +1150,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets a local variable declaration, for example `x = null` and * `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1252,7 +1162,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets the `n`th local variable declaration. For example, the second * (`n = 1`) declaration is `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1266,7 +1176,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { /** * A local constant declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1276,7 +1186,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { /** * Gets a local constant declaration, for example `x = 1` and `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1288,7 +1198,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { * Gets the `n`th local constant declaration. For example, the second * (`n = 1`) declaration is `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1302,7 +1212,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { /** * A `using` declaration statement, for example * - * ``` + * ```csharp * using FileStream f = File.Open("settings.xml"); * ``` */ @@ -1323,7 +1233,7 @@ class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { /** * An empty statement, for example line 2 in * - * ``` + * ```csharp * while (true) do { * ; * } @@ -1336,7 +1246,7 @@ class EmptyStmt extends Stmt, @empty_stmt { /** * An `unsafe` statement, for example * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1355,7 +1265,7 @@ class UnsafeStmt extends Stmt, @unsafe_stmt { /** * A `fixed` statement, for example lines 3--5 in * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1386,7 +1296,7 @@ class FixedStmt extends Stmt, @fixed_stmt { /** * A label statement, for example line 7 in * - * ``` + * ```csharp * while (true) { * if (done) * goto exit; @@ -1409,7 +1319,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * * For example, the `return` statement in * - * ``` + * ```csharp * exit: * return MetadataToken.Zero; * ``` @@ -1431,7 +1341,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * A statement defining a local function. For example, * the statement on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index 3cd6ef14d41..41127586a89 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -96,7 +96,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * In the following example, only the class `C2` has a parent namespace declaration * returned by `getParentNamespaceDeclaration`. * - * ``` + * ```csharp * class C1 { ... } * * namespace N { @@ -140,7 +140,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the methods `A.M1()`, `B.M3()`, and `C.M4()` in * - * ``` + * ```csharp * class A { * public void M1() { } * private void M2() { } @@ -165,7 +165,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * For example, `C` has the callables `A.get_P1`, `A.set_P1`, `A.M2()`, `B.get_P2`, * `B.set_P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -194,7 +194,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the members `A.P1`, `A.M2()`, `B.P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -368,7 +368,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ /** * A nested type, for example `class B` in * - * ``` + * ```csharp * class A { * class B { * ... @@ -608,7 +608,7 @@ class DecimalType extends SimpleType, @decimal_type { /** * An `enum`. For example * - * ``` + * ```csharp * enum Parity { * Even, * Odd @@ -622,7 +622,7 @@ class Enum extends ValueType, @enum_type { * * For example, the underlying type of `Parity` is `int` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd @@ -635,11 +635,12 @@ class Enum extends ValueType, @enum_type { * Gets an `enum` constant declared in this `enum`, for example `Even` * and `Odd` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd * } + * ``` */ EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this } @@ -652,7 +653,7 @@ class Enum extends ValueType, @enum_type { /** * A `struct`, for example * - * ``` + * ```csharp * struct S { * ... * } @@ -706,7 +707,7 @@ private predicate isNonOverridden(Member m) { not m.(Virtualizable).isOverridden /** * A `class`, for example * - * ``` + * ```csharp * class C { * ... * } @@ -719,7 +720,7 @@ class Class extends RefType, @class_type { } * * For example, the class with fields `X` and `Y` in * - * ``` + * ```csharp * new { X = 0, Y = 0 }; * ``` */ @@ -748,7 +749,7 @@ class StringType extends Class { /** * An `interface`, for example * - * ``` + * ```csharp * interface I { * ... * } @@ -759,7 +760,7 @@ class Interface extends RefType, @interface_type { } /** * A `delegate` type, for example * - * ``` + * ```csharp * delegate int D(int p); * ``` */ @@ -769,12 +770,6 @@ class DelegateType extends RefType, Parameterizable, @delegate_type { /** Gets the annotated return type of this delegate. */ AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } - - /** Holds if this delegate returns a `ref`. */ - deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() } - - /** Holds if this delegate returns a `ref readonly`. */ - deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() } } /** @@ -965,7 +960,7 @@ class TypeMention extends @type_mention { * Gets the element to which this type mention belongs, if any. * For example, `IEnumerable` belongs to parameter `p` in * - * ``` + * ```csharp * void M(IEnumerable p) { } * ``` */ @@ -975,7 +970,7 @@ class TypeMention extends @type_mention { * Gets the parent of this type mention, if any. * For example, the parent of `int` is `IEnumerable` in * - * ``` + * ```csharp * void M(IEnumerable p) { * ... * } diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index daa1fb7b49a..2c7545c7609 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -10,9 +10,75 @@ private import Caching * equal modulo identity conversions and type parameters. */ module Gvn { + /** + * Gets the name of type `t`, including the enclosing type of `t` as a qualifier, + * but only if the enclosing type is not a `GenericType`. + */ + string getNameNested(Type t) { + if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType + then result = t.getName() + else result = getNameNested(t.(NestedType).getDeclaringType()) + "." + t.getName() + } + + /** + * A generic type. This is either a type with a type parameter, a type with + * a type argument, or a nested type with a generic enclosing type. + * + * In this class, type parameters and type arguments are collectively referred + * to as "arguments". + */ + class GenericType extends Type { + GenericType() { + exists(this.getChild(0)) + or + this.(NestedType).getDeclaringType() instanceof GenericType + } + + /** Gets the generic containing type, if any. */ + GenericType getGenericDeclaringType() { result = this.(NestedType).getDeclaringType() } + + /** + * Gets the number of arguments of the generic containing type, or 0 if there + * is no generic containing type. + */ + int getNumberOfDeclaringArguments() { + result = this.getGenericDeclaringType().getNumberOfArguments() + or + not exists(this.getGenericDeclaringType()) and result = 0 + } + + /** Gets the number of arguments of this type, not taking nested types into account. */ + int getNumberOfArgumentsSelf() { result = count(int i | exists(this.getChild(i)) and i >= 0) } + + /** Gets the number of arguments of this type, taking nested types into account. */ + int getNumberOfArguments() { + result = this.getNumberOfDeclaringArguments() + this.getNumberOfArgumentsSelf() + } + + /** Gets the `i`th argument of this type, taking nested types into account. */ + Type getArgument(int i) { + result = this.getGenericDeclaringType().getArgument(i) + or + exists(int offset | + offset = this.getNumberOfDeclaringArguments() and + result = this.getChild(i - offset) and + i >= offset + ) + } + + /** Gets a textual representation of this type, taking nested types into account. */ + string toStringNested() { + exists(string name | name = getNameNested(this) | + result = this.getGenericDeclaringType().toStringNested() + "." + name + or + not exists(this.getGenericDeclaringType()) and result = name + ) + } + } + private class LeafType extends Type { LeafType() { - not exists(this.getAChild()) and + not this instanceof GenericType and not this instanceof TypeParameter and not this instanceof DynamicType } @@ -28,14 +94,22 @@ module Gvn { or this = TArrayTypeKind(_, _) and result = 1 or - exists(UnboundGenericType ugt | this = TConstructedType(ugt) | - result = ugt.getNumberOfTypeParameters() + exists(GenericType t | this = TConstructedType(t.getSourceDeclaration()) | + result = t.getNumberOfArguments() ) } - /** Gets a textual representation of this kind when applied to arguments `args`. */ + /** Gets the source declaration type that this kind corresponds to, if any. */ + GenericType getConstructedSourceDeclaration() { this = TConstructedType(result) } + + /** + * Gets a textual representation of this kind when applied to arguments `args`. + * + * This predicate is restricted to built-in generics (pointers, nullables, and + * arrays). + */ bindingset[args] - string toString(string args) { + string toStringBuiltin(string args) { this = TPointerTypeKind() and result = args + "*" or this = TNullableTypeKind() and result = args + "?" @@ -43,14 +117,14 @@ module Gvn { exists(int rnk | this = TArrayTypeKind(_, rnk) | result = args + "[" + concat(int i | i in [0 .. rnk - 2] | ",") + "]" ) - or - exists(UnboundGenericType ugt | this = TConstructedType(ugt) | - result = ugt.getNameWithoutBrackets() + "<" + args + ">" - ) } /** Gets a textual representation of this kind. */ - string toString() { result = toString("") } + string toString() { + result = this.toStringBuiltin("") + or + result = this.getConstructedSourceDeclaration().toStringNested() + } /** Gets the location of this kind. */ Location getLocation() { result instanceof EmptyLocation } @@ -64,11 +138,9 @@ module Gvn { or t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank())) or - result = TConstructedType(t.(ConstructedType).getUnboundGeneric()) + result = TConstructedType(t.getSourceDeclaration()) or - result = TConstructedType(t.(TupleType).getUnderlyingType().getUnboundGeneric()) - or - result = TConstructedType(t) + result = TConstructedType(t.(TupleType).getUnderlyingType().getSourceDeclaration()) } /** @@ -107,7 +179,7 @@ module Gvn { override CompoundTypeKind getKind() { result = l.getKind() } } - private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) { + private ConstructedGvnTypeList gvnConstructed(GenericType t, CompoundTypeKind k, int i) { result = TConstructedGvnTypeNil(k) and i = -1 and k = getTypeKind(t) @@ -118,14 +190,16 @@ module Gvn { } pragma[noinline] - private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) } + private GvnType gvnTypeArgument(GenericType t, int i) { + result = getGlobalValueNumber(t.getArgument(i)) + } pragma[noinline] private predicate gvnConstructedCons( - Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail + GenericType t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChild(t, i) + head = gvnTypeArgument(t, i) } private class ConstructedGvnTypeList extends TConstructedGvnTypeList { @@ -150,17 +224,47 @@ module Gvn { ) } + /** + * Gets a textual representation of this constructed type, restricted + * to the prefix `t` of the underlying source declaration type. + * + * The `toString()` calculation needs to be split up into prefixes, in + * order to apply the type arguments correctly. For example, a source + * declaration type `A<>.B.C<,>` applied to types `int, string, bool` + * needs to be printed as `A.B.C`. + */ + language[monotonicAggregates] + private string toStringConstructed(GenericType t) { + t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and + exists(int offset, int children, string name, string nameArgs | + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = getNameNested(t) and + if children = 0 + then nameArgs = name + else + exists(string offsetArgs | + offsetArgs = + concat(int i | + i in [offset .. offset + children - 1] + | + this.getArg(i).toString(), "," order by i + ) and + nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + ) + | + offset = 0 and result = nameArgs + or + result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs + ) + } + language[monotonicAggregates] string toString() { - exists(CompoundTypeKind k, string args | - k = this.getKind() and - args = - concat(int i | - i in [0 .. k.getNumberOfTypeParameters() - 1] - | - this.getArg(i).toString(), "," order by i - ) and - result = k.toString(args) + exists(CompoundTypeKind k | k = this.getKind() | + result = k.toStringBuiltin(this.getArg(0).toString()) + or + result = this.toStringConstructed(k.getConstructedSourceDeclaration()) ) } @@ -366,7 +470,13 @@ module Gvn { TArrayTypeKind(int dim, int rnk) { exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank()) } or - TConstructedType(UnboundGenericType ugt) { exists(ugt.getATypeParameter()) } + TConstructedType(GenericType sourceDecl) { + sourceDecl = any(GenericType t).getSourceDeclaration() and + not sourceDecl instanceof PointerType and + not sourceDecl instanceof NullableType and + not sourceDecl instanceof ArrayType and + not sourceDecl instanceof TupleType + } cached newtype TGvnType = @@ -575,7 +685,7 @@ module Unification { private import Cached /** - * Holds if types `t1` and `t2` are unifiable. That is, is it possible to replace + * Holds if types `t1` and `t2` are unifiable. That is, it is possible to replace * all type parameters in `t1` and `t2` with some (other) types to make the two * substituted terms equal. * @@ -612,7 +722,7 @@ module Unification { } /** - * Holds if type `t1` subsumes type `t2`. That is, is it possible to replace all + * Holds if type `t1` subsumes type `t2`. That is, it is possible to replace all * type parameters in `t1` with some (other) types to make the two types equal. * * The same limitations that apply to the predicate `unifiable()` apply to this diff --git a/csharp/ql/src/semmle/code/csharp/Using.qll b/csharp/ql/src/semmle/code/csharp/Using.qll index 9b1362cf9dc..cc165873d41 100644 --- a/csharp/ql/src/semmle/code/csharp/Using.qll +++ b/csharp/ql/src/semmle/code/csharp/Using.qll @@ -17,7 +17,7 @@ class UsingDirective extends Element, @using_directive { * * Example: * - * ``` + * ```csharp * using System; * * namespace N { diff --git a/csharp/ql/src/semmle/code/csharp/Variable.qll b/csharp/ql/src/semmle/code/csharp/Variable.qll index 0d1d462f888..183d08c1eaa 100644 --- a/csharp/ql/src/semmle/code/csharp/Variable.qll +++ b/csharp/ql/src/semmle/code/csharp/Variable.qll @@ -36,7 +36,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Holds if this variable is captured by a nested callable. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -51,7 +51,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Gets a callable that captures this variable, if any. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -77,7 +77,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * A parameter of a parameterizable declaration (callable, delegate, or indexer). * For example, `p` in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -89,7 +89,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Gets the position of this parameter. For example, the position of `x` is * 0 and the position of `y` is 1 in * - * ``` + * ```csharp * void M(int x, int y) { * ... * } @@ -103,7 +103,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a normal value parameter. For example, `p` * is a value parameter in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -115,7 +115,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a reference parameter. For example, `p` * is a reference parameter in * - * ``` + * ```csharp * void M(ref int p) { * ... * } @@ -127,7 +127,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is an output parameter. For example, `p` * is an output parameter in * - * ``` + * ```csharp * void M(out int p) { * ... * } @@ -139,7 +139,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a value type that is passed in by reference. * For example, `p` is an input parameter in * - * ``` + * ```csharp * void M(in int p) { * ... * } @@ -154,7 +154,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a parameter array. For example, `args` * is a parameter array in * - * ``` + * ```csharp * void M(params string[] args) { * ... * } @@ -167,7 +167,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * For example, `list` is the first parameter of the extension method * `Count` in * - * ``` + * ```csharp * static int Count(this IEnumerable list) { * ... * } @@ -198,7 +198,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Gets the default value of this parameter, if any. For example, the * default value of `numberOfTries` is `3` in * - * ``` + * ```csharp * void Connect(int numberOfTries = 3) { * ... * } @@ -220,7 +220,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * * Example: * - * ``` + * ```csharp * class C { * void M(int x, int y = 2, int z = 3) { } * @@ -249,7 +249,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * special `value` parameter. For example, the `value` parameter of * `set_ReadOnly` in * - * ``` + * ```csharp * public bool ReadOnly { * get { * return flags.HasValue(Attribute.ReadOnly); @@ -272,7 +272,7 @@ class ImplicitAccessorParameter extends Parameter { * A local variable, declared within the scope of a callable. For example, * the variables `total` and `s` in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -290,7 +290,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * For example, the initializer of `total` is `0`, and `s` has no * initializer, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -305,7 +305,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * Holds if this variable is implicitly typed. For example, the variable * `s` is implicitly type, and the variable `total` is not, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -338,7 +338,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * A local constant, modeled as a special kind of local variable. For example, * the local constant `maxTries` in * - * ``` + * ```csharp * void M() { * const int maxTries = 10; * ... @@ -356,7 +356,7 @@ class LocalConstant extends LocalVariable, @local_constant { /** * A field. For example, the fields `x` and `y` in * - * ``` + * ```csharp * struct Coord { * public int x, y; * } @@ -368,7 +368,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Gets the initial value of this field, if any. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -380,7 +380,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Holds if this field has an initial value. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -413,7 +413,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * A member constant, modeled a special kind of field. For example, * the constant `Separator` in * - * ``` + * ```csharp * class Path { * const char Separator = `\\`; * ... @@ -428,7 +428,7 @@ class MemberConstant extends Field, @constant { /** * An `enum` member constant. For example, `ReadOnly` and `Shared` in * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared = 2 @@ -445,7 +445,7 @@ class EnumConstant extends MemberConstant { * Gets the underlying integral type of this `enum` constant. For example, * the underlying type of `Attribute` is `byte` in * - * ``` + * ```csharp * enum Attribute : byte { * ReadOnly = 1, * Shared = 2 @@ -460,7 +460,7 @@ class EnumConstant extends MemberConstant { * In this example, `ReadOnly` has an explicit value but * `Shared` does not have an explicit value. * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared diff --git a/csharp/ql/src/semmle/code/csharp/XML.qll b/csharp/ql/src/semmle/code/csharp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/csharp/ql/src/semmle/code/csharp/XML.qll +++ b/csharp/ql/src/semmle/code/csharp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll index a51ed63e49b..f63fd7227f0 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll @@ -52,7 +52,7 @@ class Assertion extends MethodCall { * Moreover, this assertion corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(BasicBlock bb | * bb.getANode() = this.getAControlFlowNode() | * bb.immediatelyDominates(succ) @@ -100,7 +100,7 @@ class Assertion extends MethodCall { or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = bb.getAPredecessor() | // this.strictlyDominatesSplit(pred) // ) and diff --git a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll index 4a485ba767e..5d083679f9d 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll @@ -348,11 +348,12 @@ class CompareMethodCallComparisonTest extends ComparisonTest, TCompareCall { } * A comparison test using a user-defined comparison operator, for example * `this == other` on line 3 in * - * ``` + * ```csharp * public class C { * public static bool operator ==(C lhs, C rhs) => true; * public bool Is(C other) => this == other; * } + * ``` */ class OperatorCallComparisonTest extends ComparisonTest, TComparisonOperatorCall { } diff --git a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll index 7815890b51a..0e01f7f7ab7 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll @@ -23,7 +23,7 @@ predicate isConstantCondition(Expr e, boolean b) { * Holds if comparison operation `co` is constant with the Boolean value `b`. * For example, the comparison `x > x` is constantly `false` in * - * ``` + * ```csharp * int MaxWrong(int x, int y) => x > x ? x : y; * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll index a222c74281b..4e007d61737 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll @@ -12,7 +12,7 @@ private import semmle.code.csharp.frameworks.system.Text * invocation will take place, unless the expression is already a string. * For example, `o` and `o.ToString()` on lines 2 and 3, respectively, in * - * ``` + * ```csharp * void Hello(object o) { * Console.WriteLine("Hello, " + o); * Console.WriteLine("Hello, " + o.ToString()); diff --git a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll index c6532eebcb3..83de1b9d294 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll @@ -6,7 +6,7 @@ import csharp * An attribute of type `System.Runtime.Versioning.TargetFrameworkAttribute`, * specifying the target framework of an assembly. For example * - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` */ @@ -20,7 +20,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework name of this attribute. For example, the framework name of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework,Version=v4.6.1"`. @@ -33,7 +33,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework type of this attribute. For example, the framework type of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework"`. Other framework types include `".NETStandard"` and `".NETCoreApp"`. @@ -42,7 +42,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework version of this attribute. For example, the framework version of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `"4.6.1"`. Note that you can use the `Version` class to compare versions, for example diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll index 03f98b36d32..9dc2c30eb8e 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -34,7 +34,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -52,7 +52,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -89,7 +89,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -112,7 +112,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -134,7 +134,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -161,7 +161,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -195,7 +195,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -219,7 +219,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -244,7 +244,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -447,7 +447,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -455,7 +455,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll index a8ba5f85893..a82416189fd 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll @@ -118,7 +118,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * Moreover, this control flow element corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.immediatelyControls(succ, s) @@ -162,7 +162,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = controlled.getAPredecessor() | // this.controlsBlockSplit(pred, s) // ) and @@ -192,7 +192,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled, s) @@ -216,7 +216,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled.getAControlFlowNode().getBasicBlock(), s) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index bfd7487f82f..74ed9d4fac9 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -48,7 +48,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -80,7 +80,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -113,7 +113,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -151,7 +151,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -201,7 +201,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -221,7 +221,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -501,7 +501,7 @@ module ControlFlow { private class WriteAccessNoNodeExpr extends WriteAccess, NoNodeExpr { WriteAccessNoNodeExpr() { // For example a write to a static field, `Foo.Bar = 0`. - forall(Expr e | e = this.(QualifiableExpr).getQualifier() | e instanceof NoNodeExpr) + forall(Expr e | e = this.getAChildExpr() | e instanceof NoNodeExpr) } } @@ -517,7 +517,6 @@ module ControlFlow { e = any(QualifiableExpr qe | not qe instanceof ExtensionMethodCall and - not qe.isConditional() and result = qe.getChild(i) ) or @@ -553,7 +552,17 @@ module ControlFlow { * not evaluated, only the qualifier and the indexer arguments (if any). */ private class QualifiedWriteAccess extends WriteAccess, QualifiableExpr { - QualifiedWriteAccess() { this.hasQualifier() } + QualifiedWriteAccess() { + this.hasQualifier() + or + // Member initializers like + // ```csharp + // new Dictionary() { [0] = "Zero", [1] = "One", [2] = "Two" } + // ``` + // need special treatment, because the the accesses `[0]`, `[1]`, and `[2]` + // have no qualifier. + this = any(MemberInitializer mi).getLValue() + } } /** A normal or a (potential) dynamic call to an accessor. */ @@ -572,7 +581,7 @@ module ControlFlow { * that the accessor is called *after* the assigned value has been evaluated. * In the example above, this means we want a CFG that looks like * - * ``` + * ```csharp * x -> 0 -> set_Prop -> x.Prop = 0 * ``` */ @@ -646,7 +655,7 @@ module ControlFlow { cfe = any(AssignOperationWithExpandedAssignment a | result = first(a.getExpandedAssignment())) or - cfe = any(ConditionallyQualifiedExpr cqe | result = first(cqe.getChildExpr(-1))) + cfe = any(ConditionallyQualifiedExpr cqe | result = first(getExprChildElement(cqe, 0))) or cfe = any(ArrayCreation ac | @@ -872,7 +881,7 @@ module ControlFlow { c = getValidSelfCompletion(result) or // Qualifier exits with a `null` completion - result = cqe.getChildExpr(-1) and + result = getExprChildElement(cqe, 0) and c = TRec(TLastRecSpecificCompletion(any(NullnessCompletion nc | nc.isNull()))) ) or @@ -1444,16 +1453,16 @@ module ControlFlow { ) or exists(ConditionallyQualifiedExpr parent, int i | - cfe = last(parent.getChildExpr(i), c) and + cfe = last(getExprChildElement(parent, i), c) and c instanceof NormalCompletion and - not c.(NullnessCompletion).isNull() + if i = 0 then c.(NullnessCompletion).isNonNull() else any() | // Post-order: flow from last element of last child to element itself - i = max(int j | exists(parent.getChildExpr(j))) and + i = max(int j | exists(getExprChildElement(parent, j))) and result = parent or // Standard left-to-right evaluation - result = first(parent.getChildExpr(i + 1)) + result = first(getExprChildElement(parent, i + 1)) ) or // Post-order: flow from last element of thrown expression to expression itself diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 14438ff1418..2d3eac6c79b 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -62,7 +62,7 @@ abstract class AbstractValue extends TAbstractValue { * * Such values only propagate through adjacent reads, for example, in * - * ``` + * ```csharp * int M() * { * var x = new string[]{ "a", "b", "c" }.ToList(); @@ -350,7 +350,7 @@ class DereferenceableExpr extends Expr { * * For example, if the case statement `case string s` matches in * - * ``` + * ```csharp * switch (o) * { * case string s: @@ -562,7 +562,7 @@ class AccessOrCallExpr extends Expr { * * Examples: * - * ``` + * ```csharp * x.Foo.Bar(); // SSA qualifier: SSA definition for `x.Foo` * x.Bar(); // SSA qualifier: SSA definition for `x` * x.Foo().Bar(); // SSA qualifier: SSA definition for `x` @@ -607,7 +607,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * * For example, the property call `x.Field.Property` on line 3 is guarded in * - * ``` + * ```csharp * string M(C x) { * if (x.Field.Property != null) * return x.Field.Property.ToString(); @@ -621,7 +621,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * guard, whereas the null-guard on `stack.Pop()` on line 4 is not (invoking * `Pop()` twice on a stack does not yield the same result): * - * ``` + * ```csharp * string M(Stack stack) { * if (stack == null) * return ""; @@ -686,7 +686,7 @@ class GuardedExpr extends AccessOrCallExpr { * into account. That is, one control flow node belonging to an expression may * be guarded, while another split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -736,7 +736,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { * is, one data flow node belonging to an expression may be guarded, while another * split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -1262,7 +1262,7 @@ module Internal { * * For example, if the case statement `case ""` matches in * - * ``` + * ```csharp * switch (o) * { * case "": diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll index 36aa4e926e0..b497a819f1b 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll @@ -635,7 +635,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion { * * Example: * - * ``` + * ```csharp * while (...) { * ... * break; @@ -656,7 +656,7 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion { /** * A nested completion. For example, in * - * ``` + * ```csharp * void M(bool b) * { * try diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll index 5a78344a391..dcbe9726bb2 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -278,7 +278,7 @@ module InitializerSplitting { * A split for non-static member initializers belonging to a given non-static * constructor. For example, in * - * ``` + * ```csharp * class C * { * int Field1 = 0; @@ -301,7 +301,7 @@ module InitializerSplitting { * on the two constructors. This is in order to generate CFGs for the two * constructors that mimic * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -312,7 +312,7 @@ module InitializerSplitting { * * and * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -467,7 +467,7 @@ module FinallySplitting { * A split for elements belonging to a `finally` block, which determines how to * continue execution after leaving the `finally` block. For example, in * - * ``` + * ```csharp * try * { * if (!M()) @@ -599,7 +599,7 @@ module FinallySplitting { // If this split is normal, and an outer split can exit based on a inherited // completion, we need to exit this split as well. For example, in // - // ``` + // ```csharp // bool done; // try // { @@ -677,7 +677,7 @@ module ExceptionHandlerSplitting { * A split for elements belonging to a `catch` clause, which determines the type of * exception to handle. For example, in * - * ``` + * ```csharp * try * { * if (M() > 0) @@ -698,11 +698,11 @@ module ExceptionHandlerSplitting { * ``` * * all control flow nodes in - * ``` + * ```csharp * catch (ArgumentException e) * ``` * and - * ``` + * ```csharp * catch (ArithmeticException e) when (e.Message != null) * ``` * have two splits: one representing the `try` block throwing an `ArgumentException`, @@ -853,7 +853,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -892,7 +892,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -969,7 +969,7 @@ module BooleanSplitting { * A split for elements that can reach a condition where this split determines * the Boolean value that the condition evaluates to. For example, in * - * ``` + * ```csharp * if (b) * Console.WriteLine("b is true"); * if (!b) @@ -1171,7 +1171,7 @@ module LoopUnrollingSplitting { * A split for loops where the body is guaranteed to be executed at least once, and * can therefore be unrolled in the control flow graph. For example, in * - * ``` + * ```csharp * void M(string[] args) * { * if (args.Length == 0) @@ -1338,7 +1338,7 @@ predicate succExitSplits(ControlFlowElement pred, Splits predSplits, Callable su * * For the successor relation * - * ``` + * ```ql * succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll index 3f265236fb4..8e34ac19a0d 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll @@ -59,7 +59,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * if (x < 0) * return 0; * else @@ -95,7 +95,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * int? M(string s) => s?.Length; * ``` * @@ -134,7 +134,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * switch (x) { * case 0 : * return 0; @@ -181,7 +181,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * foreach (var arg in args) * { * yield return arg; @@ -228,7 +228,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * void M() * { * return; @@ -249,7 +249,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -277,7 +277,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) { @@ -302,7 +302,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -333,7 +333,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -361,7 +361,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 1f08f81548a..fac6c60343e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -3,7 +3,6 @@ */ import csharp -private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic @@ -16,24 +15,59 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.system.Xml +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.DataFlowPublic private import semmle.code.csharp.dataflow.internal.DelegateDataFlow +// import `LibraryTypeDataFlow` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.EntityFramework +private import semmle.code.csharp.frameworks.JsonNET private newtype TAccessPath = TNilAccessPath() or - TAccessPathConsNil(Content c) + TConsAccessPath(Content head, AccessPath tail) { + tail = TNilAccessPath() + or + exists(LibraryTypeDataFlow ltdf | + ltdf.requiresAccessPath(head, tail) and + tail.length() < accessPathLimit() + ) + or + tail = AccessPath::singleton(_) and + head instanceof ElementContent + } -/** An access path of length 0 or 1. */ +/** An access path. */ class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ - Content getHead() { this = TAccessPathConsNil(result) } + Content getHead() { this = TConsAccessPath(result, _) } + + /** Gets the tail of this access path, if any. */ + AccessPath getTail() { this = TConsAccessPath(_, result) } + + /** Gets the length of this access path. */ + int length() { + this = TNilAccessPath() and result = 0 + or + result = 1 + this.getTail().length() + } + + /** Gets the access path obtained by dropping the first `i` elements, if any. */ + AccessPath drop(int i) { + i = 0 and result = this + or + result = this.getTail().drop(i - 1) + } /** Holds if this access path contains content `c`. */ - predicate contains(Content c) { this = TAccessPathConsNil(c) } + predicate contains(Content c) { c = this.drop(_).getHead() } /** Gets a textual representation of this access path. */ string toString() { - result = this.getHead().toString() + exists(Content head, AccessPath tail | + head = this.getHead() and + tail = this.getTail() and + if tail.length() = 0 then result = head.toString() else result = head + ", " + tail + ) or this = TNilAccessPath() and result = "" @@ -45,10 +79,22 @@ module AccessPath { /** Gets the empty access path. */ AccessPath empty() { result = TNilAccessPath() } + /** Gets a singleton access path containing `c`. */ + AccessPath singleton(Content c) { result = TConsAccessPath(c, TNilAccessPath()) } + + /** Gets the access path obtained by concatenating `head` onto `tail`. */ + AccessPath cons(Content head, AccessPath tail) { result = TConsAccessPath(head, tail) } + + /** Gets the singleton "element content" access path. */ + AccessPath element() { result = singleton(any(ElementContent c)) } + /** Gets a singleton property access path. */ AccessPath property(Property p) { - result = TAccessPathConsNil(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) + result = singleton(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) } + + /** Gets an access path representing a property inside a collection. */ + AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) } } /** An unbound callable. */ @@ -61,25 +107,9 @@ class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } private newtype TCallableFlowSource = TCallableFlowSourceQualifier() or - TCallableFlowSourceArg(int i) { hasArgumentPosition(_, i) } or + TCallableFlowSourceArg(int i) { i = any(Parameter p).getPosition() } or TCallableFlowSourceDelegateArg(int i) { hasDelegateArgumentPosition(_, i) } -private predicate hasArgumentPosition(SourceDeclarationCallable callable, int position) { - exists(int arity | - if callable.getAParameter().isParams() - then - arity = - max(Call call | - call.getTarget().getSourceDeclaration() = callable - | - call.getNumberOfArguments() - ) - else arity = callable.getNumberOfParameters() - | - position in [0 .. arity - 1] - ) -} - private predicate hasDelegateArgumentPosition(SourceDeclarationCallable c, int i) { exists(DelegateType dt | dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() @@ -173,7 +203,15 @@ class CallableFlowSink extends TCallableFlowSink { class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier { override string toString() { result = "qualifier" } - override Expr getSink(Call c) { result = c.getChild(-1) } + override Expr getSink(Call c) { + result = c.getChild(-1) + or + // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` + result.(CollectionInitializer).getAnElementInitializer() = c + or + // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` + result.(ObjectInitializer).getAMemberInitializer().getLValue() = c + } } /** A flow sink specification: return value. */ @@ -211,10 +249,20 @@ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { override Type getSinkType(Call c) { result = this.getArgument(c).getType() } } +private predicate isCollectionType(ValueOrRefType t) { + t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and + not t instanceof StringType +} + /** Gets the flow source for argument `i` of callable `callable`. */ -private CallableFlowSourceArg getFlowSourceArg(SourceDeclarationCallable callable, int i) { +private CallableFlowSourceArg getFlowSourceArg( + SourceDeclarationCallable callable, int i, AccessPath ap +) { i = result.getArgumentIndex() and - hasArgumentPosition(callable, i) + exists(Parameter p | + p = callable.getParameter(i) and + if isCollectionType(p.getType()) then ap = AccessPath::element() else ap = AccessPath::empty() + ) } /** Gets the flow source for argument `i` of delegate `callable`. */ @@ -297,7 +345,27 @@ abstract class LibraryTypeDataFlow extends Type { pragma[nomagic] predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue + ) { + none() + } + + /** + * Holds if the access path obtained by concatenating `head` onto `tail` is + * needed for a summary specified by `callableFlow()`. + * + * This predicate is needed for QL technical reasons only (the IPA type used + * to represent access paths needs to be bounded). + */ + predicate requiresAccessPath(Content head, AccessPath tail) { none() } + + /** + * Holds if values stored inside `content` are cleared on objects passed as + * arguments of type `source` to calls that target `callable`. + */ + pragma[nomagic] + predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable ) { none() } @@ -392,8 +460,7 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m.getDeclaringType() = getABaseType*() and - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + m = this.getAMethod("ToString") and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() } @@ -441,41 +508,48 @@ class SystemIOStringReaderFlow extends LibraryTypeDataFlow, SystemIOStringReader /** Data flow for `System.String`. */ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - constructorFlow(source, sink, c) and preservesValue = false + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = false or - methodFlow(source, sink, c, preservesValue) + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof CharType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m = getAMethod() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + m = this.getAMethod("ToString") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getSplitMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and + preservesValue = false or m = getReplaceMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -487,20 +561,22 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getSubstringMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getCloneMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getInsertMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -512,55 +588,54 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getNormalizeMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getRemoveMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getAMethod() and - ( - m - .getName() - .regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + m.getName().regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getConcatMethod() and - ( - source = getFlowSourceArg(m, _) and + exists(int i | + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) or m = getCopyMethod() and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getJoinMethod() and - ( - source = getFlowSourceArg(m, _) and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = getFlowSourceArg(m, [0, 1], sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getFormatMethod() and exists(int i | (m.getParameter(0).getType() instanceof SystemIFormatProviderInterface implies i != 0) and - source = getFlowSourceArg(m, i) and + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -569,53 +644,72 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { /** Data flow for `System.Text.StringBuilder`. */ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringBuilderClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = true or - methodFlow(source, sink, c) - ) and - preservesValue = false + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) + ) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m.getDeclaringType() = getABaseType*() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + exists(string name | m = this.getAMethod(name) | + name = "ToString" and source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) - or - m = getAMethod() and - exists(int i, Type t | - m.getName().regexpMatch("Append(Format|Line)?") and - t = m.getParameter(i).getType() and - source = getFlowSourceArg(m, i) and - sink = TCallableFlowSinkQualifier() - | - t instanceof StringType or - t instanceof ObjectType + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false + or + exists(int i, Type t | + name.regexpMatch("Append(Format|Line)?") and + t = m.getParameter(i).getType() and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = [TCallableFlowSinkQualifier().(TCallableFlowSink), TCallableFlowSinkReturn()] and + sinkAp = AccessPath::element() and + preservesValue = true + | + t instanceof StringType or + t instanceof ObjectType + ) ) } + + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable + ) { + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } } /** Data flow for `System.Lazy<>`. */ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { override predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue ) { + preservesValue = true and exists(SystemFuncDelegateType t, int i | t.getNumberOfTypeParameters() = 1 | c.(Constructor).getDeclaringType() = this and c.getParameter(i).getType().getSourceDeclaration() = t and @@ -627,50 +721,84 @@ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { } } -/** - * Data flow for `System.Collections.IEnumerable`, `System.Collections.Generic.IEnumerable<>`, - * and their sub types (for example `System.Collections.Generic.List<>`). - */ -class IEnumerableFlow extends LibraryTypeDataFlow { - IEnumerableFlow() { - exists(RefType t | t = this.(RefType).getABaseType*() | - t instanceof SystemCollectionsIEnumerableInterface +/** Data flow for `System.Collections.IEnumerable` (and sub types). */ +class IEnumerableFlow extends LibraryTypeDataFlow, RefType { + IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + ( + methodFlowLINQExtensions(source, sourceAp, sink, sinkAp, c) or - t instanceof SystemCollectionsGenericIEnumerableTInterface + c = this.getFind() and + sourceAp = AccessPath::element() and + sinkAp = AccessPath::empty() and + if c.(Method).isStatic() + then + source = TCallableFlowSourceArg(0) and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 1, 0) + ) + else ( + source = TCallableFlowSourceQualifier() and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 0, 0) + ) + ) or - t.(ConstructedInterface).getUnboundGeneric() instanceof - SystemCollectionsGenericIEnumerableTInterface + exists(string name, int arity | + arity = c.getNumberOfParameters() and + c = this.getAMethod(name) + | + name = "Add" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name = "AddRange" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + or + exists(Property current | + name = "GetEnumerator" and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(current) and + current = c.getReturnType().(ValueOrRefType).getProperty("Current") + ) + or + name = "Repeat" and + c.(Method).isStatic() and + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + name = "Reverse" and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + ) ) } - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - ( - methodFlow(source, sink, c) - or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = false - } - - private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m - ) { - methodFlowLINQ(source, sink, m) - or - methodFlowSpecific(source, sink, m) - } - - /** Flow for LINQ methods. */ - private predicate methodFlowLINQ( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + /** Flow for LINQ extension methods. */ + private predicate methodFlowLINQExtensions( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.(ExtensionMethod).getExtendedType().getSourceDeclaration() = this and exists(string name, int arity | name = m.getName() and arity = m.getNumberOfParameters() | @@ -679,192 +807,239 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity = 2 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 4 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) ) or name = "All" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Any" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "AsEnumerable" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "AsQueryable" and arity = 1 and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Average" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Cast" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Concat" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Long)?Count") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "DefaultIfEmpty" and ( arity in [1 .. 2] and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or name = "Distinct" and - ( - arity in [1 .. 2] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [1 .. 2] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("ElementAt(OrDefault)?") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name = "Except" and - ( - arity in [2 .. 3] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [2 .. 3] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name.regexpMatch("(First|Single)(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "GroupBy" and ( + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 2 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or not m.getParameter(2).getType().getSourceDeclaration() instanceof SystemCollectionsGenericIEqualityComparerTInterface and source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - or - m.getParameter(2).getType().getSourceDeclaration() instanceof - SystemCollectionsGenericIEqualityComparerTInterface and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or arity in [4 .. 5] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = getDelegateFlowSinkArg(m, 3, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 1) and + sinkAp = AccessPath::element() or source = getDelegateFlowSourceArg(m, 3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -873,19 +1048,29 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [5 .. 6] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 4, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 4, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(4) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -894,269 +1079,222 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name.regexpMatch("Last(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name.regexpMatch("Max|Min|Sum") and ( arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "OfType" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("OrderBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) - or - name = "Repeat" and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "Reverse" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("Select(Many)?") and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "SelectMany" and + arity = 3 and ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Skip|Take)(While)?") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("(Skip|Take)While") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name.regexpMatch("ThenBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("To(Array|List)") and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("To(Dictionary|Lookup)") and ( arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and not m.getParameter(2).getType() instanceof DelegateType ) or arity in [3 .. 4] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name = "Union" and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Where" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Zip" and - ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - ) - ) - ) - } - - /** Flow for specific enumerables (e.g., `List` and `Stack`). */ - private predicate methodFlowSpecific( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m - ) { - m = getFind() and - if m.isStatic() - then - source = TCallableFlowSourceArg(0) and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - else ( - source = TCallableFlowSourceQualifier() and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 0, 0) - ) - ) - or - exists(string name, int arity | - name = m.getName() and - arity = m.getNumberOfParameters() and - m.getDeclaringType() = this.(RefType).getABaseType*() - | - name = "FixedSize" and + arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - or - name - .regexpMatch("GetByIndex|Peek|Pop|AsReadOnly|Clone|GetRange|MemberwiseClone|Reverse|GetEnumerator|GetValueList") and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) - or - name.regexpMatch("Add(Range)?") and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkQualifier() - ) - or - name = "Add" and - ( - arity = 2 and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() - ) - or - name.regexpMatch("Insert(Range)?") and - ( - not this instanceof StringType and - arity = 2 and - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = getDelegateFlowSourceArg(m, 2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) } @@ -1164,15 +1302,203 @@ class IEnumerableFlow extends LibraryTypeDataFlow { private SourceDeclarationMethod getFind() { exists(string name | name = result.getName() and - result.getDeclaringType() = this.(RefType).getABaseType*() + result.getDeclaringType() = this.getABaseType*() | name.regexpMatch("Find(All|Last)?") ) } - private predicate propertyFlow(Property p) { - this.(RefType).getABaseType*() = p.getDeclaringType() and - p.hasName("Values") + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable + ) { + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } +} + +/** Data flow for `System.Collections.[Generic.]ICollection` (and sub types). */ +class ICollectionFlow extends LibraryTypeDataFlow, RefType { + ICollectionFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsICollectionInterface + or + i instanceof SystemCollectionsGenericICollectionInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + exists(string name, int arity | + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() + | + name = "CopyTo" and + arity = 2 and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkArg(0) and + sinkAp = AccessPath::element() + or + name.regexpMatch("AsReadOnly|Clone") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + name.regexpMatch("Peek|Pop") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + name = "InsertRange" and + arity = 2 and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + ) + } +} + +/** Data flow for `System.Collections.[Generic.]IList` (and sub types). */ +class IListFlow extends LibraryTypeDataFlow, RefType { + IListFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIListInterface + or + i instanceof SystemCollectionsGenericIListInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + ( + exists(string name, int arity | + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() + | + name = "Insert" and + arity = 2 and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name.regexpMatch("FixedSize|GetRange") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + ) + or + c = this.getAnIndexer().getSetter() and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + c = this.getAnIndexer().getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() + ) + } +} + +/** Data flow for `System.Collections.[Generic.]IDictionary` (and sub types). */ +class IDictionaryFlow extends LibraryTypeDataFlow, RefType { + IDictionaryFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIDictionaryInterface + or + i instanceof SystemCollectionsGenericIDictionaryInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + exists(SystemCollectionsGenericKeyValuePairStruct kvp | + exists(int i | + c = this.getAConstructor() and + source = TCallableFlowSourceArg(i) and + sourceAp = sinkAp and + c.getParameter(i).getType().(ValueOrRefType).getABaseType*() instanceof + SystemCollectionsIEnumerableInterface and + sink instanceof CallableFlowSinkReturn + | + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + c = this.getProperty("Keys").getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getKeyProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getProperty("Values").getGetter() + or + c = this.getAMethod("GetValueList") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 2 + or + c = this.getAnIndexer().getSetter() + ) and + ( + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + exists(Property p | + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::property(p) and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(p) and + p = kvp.getAProperty() + ) + or + ( + c = this.getAnIndexer().getGetter() + or + c = this.getAMethod("GetByIndex") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() + ) } } @@ -1195,33 +1521,6 @@ class SystemConvertFlow extends LibraryTypeDataFlow, SystemConvertClass { } } -/** - * Data flow for WCF data contracts. - * - * Flow is defined from a WCF data contract object to any of its data member - * properties. This flow model only makes sense from a taint-tracking perspective - * (a tainted data contract object implies tainted data members). - */ -class DataContractFlow extends LibraryTypeDataFlow, DataContractClass { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = false - } - - private predicate propertyFlow(Property p) { - p.getDeclaringType() = this and - p.getAnAttribute() instanceof DataMemberAttribute - } -} - /** Data flow for `System.Web.HttpCookie`. */ class SystemWebHttpCookieFlow extends LibraryTypeDataFlow, SystemWebHttpCookie { override predicate callableFlow( @@ -1301,97 +1600,39 @@ class SystemWebUIWebControlsTextBoxFlow extends LibraryTypeDataFlow, private predicate propertyFlow(Property p) { p = getTextProperty() } } -/** - * Data flow for `System.Collections.Generic.KeyValuePair`. - * - * Flow is only considered for the value (not the key). - */ -class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericKeyValuePairStructFlow() { - this instanceof SystemCollectionsGenericKeyValuePairStruct - } - +/** Data flow for `System.Collections.Generic.KeyValuePair`. */ +class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow, + SystemCollectionsGenericKeyValuePairStruct { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - ( - constructorFlow(source, sink, c) + preservesValue = true and + exists(int i | + c.(Constructor).getDeclaringType() = this and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() + | + i = 0 and sinkAp = AccessPath::property(this.getKeyProperty()) or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = true + i = 1 and sinkAp = AccessPath::property(this.getValueProperty()) + ) } - - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c.getDeclaringType() = this and - source = getFlowSourceArg(c, 1) and - sink = TCallableFlowSinkReturn() - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericKeyValuePairStruct).getValueProperty() - } -} - -/** Data flow for `System.Collections.Generic.IEnumerator`. */ -class SystemCollectionsGenericIEnumeratorInterfaceFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericIEnumeratorInterfaceFlow() { - this instanceof SystemCollectionsGenericIEnumeratorInterface - } - - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericIEnumeratorInterface).getCurrentProperty() - } -} - -/** Data flow for `System.Collections.IEnumerator`. */ -class SystemCollectionsIEnumeratorInterfaceFlow extends LibraryTypeDataFlow, - SystemCollectionsIEnumeratorInterface { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true - } - - private predicate propertyFlow(Property p) { p = getCurrentProperty() } } /** Data flow for `System.Threading.Tasks.Task`. */ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingTasksTaskClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sink, c) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() or - methodFlow(source, sink, c) + methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true } @@ -1410,11 +1651,14 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.getDeclaringType() = this and ( m.hasName("ContinueWith") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( // flow from supplied state to supplied delegate exists(ConstructedDelegateType delegate, int i, int j, int k | @@ -1439,12 +1683,16 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT ) or m.hasName("FromResult") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() ) or m.hasName("Run") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and @@ -1453,10 +1701,11 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT ) or m.getName().regexpMatch("WhenAll|WhenAny") and + sinkAp = AccessPath::empty() and ( m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and - source = getFlowSourceArg(m, _) and + source = getFlowSourceArg(m, _, sourceAp) and sink = TCallableFlowSinkReturn() ) ) @@ -1624,13 +1873,23 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { /** Data flow for `System.Text.Encoding`. */ library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - (c = getGetBytesMethod() or c = getGetStringMethod() or c = getGetCharsMethod()) and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = false + preservesValue = false and + c = this.getAMethod() and + exists(Method m | m.getAnOverrider*().getSourceDeclaration() = c | + m = getGetBytesMethod() and + source = getFlowSourceArg(m, 0, sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + m = [getGetStringMethod(), getGetCharsMethod()] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + ) } } @@ -1766,12 +2025,13 @@ class SystemXmlXmlNamedNodeMapFlow extends LibraryTypeDataFlow, SystemXmlXmlName /** Data flow for `System.IO.Path`. */ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { c = getAMethod("Combine") and - source = getFlowSourceArg(c, _) and + source = getFlowSourceArg(c, _, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false or exists(Parameter p | @@ -1779,8 +2039,9 @@ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { c.getName().matches("Get%") and p = c.getAParameter() and p.hasName("path") and - source = getFlowSourceArg(c, p.getPosition()) and + source = getFlowSourceArg(c, p.getPosition(), sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -1837,26 +2098,21 @@ class SystemNetWebUtilityFlow extends LibraryTypeDataFlow, SystemNetWebUtility { } /** - * The `StringValues` class used in many .NET Core libraries. Requires special `LibraryTypeDataFlow` flow. + * Custom flow through `StringValues` library class. */ -class StringValues extends Struct { - StringValues() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -} +class StringValuesFlow extends LibraryTypeDataFlow, Struct { + StringValuesFlow() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -/** - * Custom flow through StringValues.StringValues library class - */ -class StringValuesFlow extends LibraryTypeDataFlow, StringValues { override predicate callableFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = any(Callable ca | this = ca.getDeclaringType()) and + c.getDeclaringType() = this and ( - source = any(CallableFlowSourceArg a) or - source = any(CallableFlowSourceQualifier q) + source instanceof CallableFlowSourceArg or + source instanceof CallableFlowSourceQualifier ) and - sink = any(CallableFlowSinkReturn r) and + sink instanceof CallableFlowSinkReturn and preservesValue = false } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index 1750a297299..279f020c0ab 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -5,7 +5,7 @@ * a `null` pointer exception (`NullReferenceException`) may be thrown. * Example: * - * ``` + * ```csharp * void M(string s) { * if (s != null) { * ... diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 7a6b5896147..adcfdfaaca7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -171,7 +171,7 @@ module Ssa { * callable. A pseudo read is inserted to make assignments to `out`/`ref` variables * live, for example line 1 in * - * ``` + * ```csharp * void M(out int i) { * i = 0; * } @@ -189,7 +189,7 @@ module Ssa { * A pseudo read is inserted to make assignments to the `ref` variable live, for example * line 2 in * - * ``` + * ```csharp * void M() { * ref int i = ref GetRef(); * i = 0; @@ -612,7 +612,7 @@ module Ssa { * For example, if `bb` is a basic block with a phi node for `v` (considered * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: * - * ``` + * ```ql * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 @@ -893,7 +893,7 @@ module Ssa { * of the field or property. For example, there is an implicit update of * `this.Field` on line 7 in * - * ``` + * ```csharp * int Field; * * void SetField(int i) { Field = i; } @@ -1359,7 +1359,7 @@ module Ssa { * site that conceivably could reach an update of the captured variable. * For example, there is an implicit update of `v` on line 4 in * - * ``` + * ```csharp * int M() { * int i = 0; * Action a = () => { i = 1; }; @@ -1559,7 +1559,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * void M() { * int i = 0; * void M2() { @@ -1736,7 +1736,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1775,7 +1775,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1845,7 +1845,7 @@ module Ssa { ( exists(ReadKind rk | liveAfterWrite(bb, i, v, rk) | // A `ref` assignment such as - // ``` + // ```csharp // ref int i = ref GetRef(); // ``` // is dead when there are no reads of or writes to `i`. @@ -2005,7 +2005,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2034,7 +2034,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2066,7 +2066,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2102,7 +2102,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2142,7 +2142,7 @@ module Ssa { * another SSA definition for the source variable, without passing through * any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2172,7 +2172,7 @@ module Ssa { * enclosing callable, or another SSA definition for the source variable, * without passing through any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2203,7 +2203,7 @@ module Ssa { * Gets a definition that ultimately defines this SSA definition and is * not itself a pseudo node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2322,7 +2322,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2349,7 +2349,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2510,7 +2510,7 @@ module Ssa { /** * Gets an input of this phi node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll index cf69f54717a..e24a793174a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll @@ -1,6 +1,4 @@ /** - * DEPRECATED. - * * Provides classes representing data flow sources for parameters of public callables. */ @@ -9,7 +7,7 @@ import csharp /** * A parameter of a public callable, for example `p` in * - * ``` + * ```csharp * public void M(int p) { * ... * } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll index 2b09436f27d..9c2cbabcd61 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll @@ -44,7 +44,7 @@ private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, bo * * For example, in * - * ``` + * ```csharp * if (b) * .... * var x = "foo"; diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index fdf0480c8ef..25ca28ea789 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -67,7 +67,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c cached private module Cached { - private import CallContext private import semmle.code.csharp.Caching cached @@ -107,7 +106,13 @@ private module Cached { /** Gets a viable run-time target for the call `call`. */ cached - DataFlowCallable viableImpl(DataFlowCall call) { result = call.getARuntimeTarget() } + DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() } +} + +import Cached + +private module DispatchImpl { + private import CallContext /** * Gets a viable run-time target for the delegate call `call`, requiring @@ -118,63 +123,40 @@ private module Cached { } /** - * Holds if the call context `ctx` reduces the set of viable run-time - * targets of call `call` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. This is the case if the + * call is a delegate call, or if the qualifier accesses a parameter of + * the enclosing callable `c` (including the implicit `this` parameter). */ - cached - predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { - c = viableImpl(ctx) and + predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { c = call.getEnclosingCallable() and - exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | - not cc instanceof EmptyCallContext + ( + exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | + not cc instanceof EmptyCallContext + ) + or + call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext() ) } - private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | cc.isArgument(ctx.getExpr(), _) ) - } - - /** - * Gets a viable run-time target for the call `call` in the context - * `ctx`. This is restricted to those call nodes for which a context - * might make a difference. - */ - cached - DotNet::Callable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInCallContext(call, _, ctx) - } - - /** - * Holds if flow returning from callable `c` to call `call` might return - * further and if this path restricts the set of call sites that can be - * returned to. - */ - cached - predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { - exists(int tgts, int ctxtgts | - c = viableImpl(call) and - ctxtgts = strictcount(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableImpl(ctx) = call.getEnclosingCallable()) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable run-time target for the call `call` in the context `ctx`. - * This is restricted to those call nodes and results for which the return - * flow from the result to `call` restricts the possible context `ctx`. - */ - cached - DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInReturn(result, call) + or + result = + call + .(NonDelegateDataFlowCall) + .getDispatchCall() + .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) } } -import Cached +import DispatchImpl /** * Gets a node that can read the value returned from `call` with return kind @@ -182,8 +164,6 @@ import Cached */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } -predicate viableCallable = viableImpl/1; - /** * A return kind. A return kind describes how a value can be returned * from a callable. @@ -278,6 +258,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { NonDelegateDataFlowCall() { this = TNonDelegateCall(cfn, dc) } + /** Gets the underlying call. */ + DispatchCall getDispatchCall() { result = dc } + override DotNet::Callable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index db0fbcf7130..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index b241a574c97..27ab1d01feb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,13 +289,94 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) + ) } /** @@ -340,21 +387,10 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,26 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -564,6 +615,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +637,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +649,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +663,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } @@ -665,9 +730,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -679,6 +741,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -689,25 +768,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index f9bac316d70..244bada9f26 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -15,6 +15,55 @@ private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate +private import semmle.code.csharp.frameworks.system.Collections + +abstract class NodeImpl extends Node { + /** Do not call: use `getEnclosingCallable()` instead. */ + abstract DataFlowCallable getEnclosingCallableImpl(); + + /** Do not call: use `getType()` instead. */ + abstract DotNet::Type getTypeImpl(); + + /** Gets the type of this node used for type pruning. */ + cached + DataFlowType getDataFlowType() { + Stages::DataFlowStage::forceCachingInSameStage() and + exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | + t0 = getCSharpType(this.getType()) + or + not exists(getCSharpType(this.getType())) and + t0 instanceof ObjectType + ) + } + + /** Do not call: use `getControlFlowNode()` instead. */ + abstract ControlFlow::Node getControlFlowNodeImpl(); + + /** Do not call: use `getLocation()` instead. */ + abstract Location getLocationImpl(); + + /** Do not call: use `toString()` instead. */ + abstract string toStringImpl(); +} + +private class ExprNodeImpl extends ExprNode, NodeImpl { + override DataFlowCallable getEnclosingCallableImpl() { + result = this.getExpr().getEnclosingCallable() + } + + override DotNet::Type getTypeImpl() { result = this.getExpr().getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) } + + override Location getLocationImpl() { result = this.getExpr().getLocation() } + + override string toStringImpl() { + result = this.getControlFlowNode().toString() + or + this = TCilExprNode(_) and + result = "CIL expression" + } +} /** Calculation of the relative order in which `this` references are read. */ private module ThisFlow { @@ -73,7 +122,7 @@ private module ThisFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { + private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } override predicate candidate( @@ -117,6 +166,14 @@ module LocalFlow { ) and scope = e2 and isSuccessor = true + or + e1 = e2.(ObjectCreation).getInitializer() and + scope = e2 and + isSuccessor = false + or + e1 = e2.(ArrayCreation).getInitializer() and + scope = e2 and + isSuccessor = false ) } @@ -151,7 +208,7 @@ module LocalFlow { result = node.asExpr() } - predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { + private predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Untainted t)) } @@ -241,6 +298,64 @@ module LocalFlow { nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable()) ) } + + predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { + exists(Ssa::Definition def | + localSsaFlowStep(def, nodeFrom, nodeTo) and + not usesInstanceField(def) + ) + or + any(LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + localFlowStepCil(nodeFrom, nodeTo) + } + + /** + * Holds if node `n` should not be included in the exposed local data/taint + * flow relations. This is the case for nodes that are only relevant for + * inter-procedurality or field-sensitivity. + */ + predicate excludeFromExposedRelations(Node n) { + n instanceof LibraryCodeNode or + n instanceof ImplicitCapturedArgumentNode or + n instanceof ImplicitDelegateOutNode or + n instanceof ImplicitDelegateArgumentNode + } +} + +pragma[noinline] +private Expr getImplicitArgument(Call c, int pos) { + result = c.getArgument(pos) and + not exists(result.getExplicitArgumentName()) +} + +pragma[nomagic] +private Expr getExplicitArgument(Call c, string name) { + result = c.getAnArgument() and + result.getExplicitArgumentName() = name +} + +/** + * Holds if `arg` is a `params` argument of `c`, for parameter `p`, and `arg` will + * be wrapped in an array by the C# compiler. + */ +private predicate isParamsArg(Call c, Expr arg, Parameter p) { + exists(Callable target, int numArgs | + target = c.getTarget() and + p = target.getAParameter() and + p.isParams() and + numArgs = c.getNumberOfArguments() and + arg = + [getImplicitArgument(c, [p.getPosition() .. numArgs - 1]), getExplicitArgument(c, p.getName())] + | + numArgs > target.getNumberOfParameters() + or + not arg.getType().isImplicitlyConvertibleTo(p.getType()) + ) } /** An argument of a C# call (including qualifier arguments). */ @@ -251,7 +366,8 @@ private class Argument extends Expr { Argument() { call = any(DispatchCall dc | - this = dc.getArgument(arg) + this = dc.getArgument(arg) and + not isParamsArg(_, this, _) or this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic() ).getCall() @@ -269,43 +385,39 @@ private class Argument extends Expr { /** * Holds if `e` is an assignment of `src` to field or property `c` of `q`. + * + * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate fieldOrPropertyAssign(Expr e, Content c, Expr src, Expr q) { - exists(FieldOrPropertyAccess fa, FieldOrProperty f, AssignableDefinition def | - def.getTargetAccess() = fa and - f = fa.getTarget() and +private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, boolean postUpdate) { + exists(FieldOrProperty f | c = f.getContent() and - src = def.getSource() and - q = fa.getQualifier() and - e = def.getExpr() - | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty - or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + ( + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + LibraryFlow::libraryFlowSummary(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) - ) -} - -/** - * Holds if `oc` has an object initializer that assigns `src` to field or - * property `c`. - */ -private predicate fieldOrPropertyInit(ObjectCreation oc, Content c, Expr src) { - exists(MemberInitializer mi, FieldOrProperty f | - mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and - f = mi.getInitializedMember() and - c = f.getContent() and - src = mi.getRValue() | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty + // Direct assignment, `q.f = src` + exists(FieldOrPropertyAccess fa, AssignableDefinition def | + def.getTargetAccess() = fa and + f = fa.getTarget() and + src = def.getSource() and + q = fa.getQualifier() and + e = def.getExpr() and + postUpdate = true + ) or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + // Object initializer, `new C() { f = src }` + exists(MemberInitializer mi | + e = q and + mi = q.(ObjectInitializer).getAMemberInitializer() and + f = mi.getInitializedMember() and + src = mi.getRValue() and + postUpdate = false ) ) } @@ -329,7 +441,7 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ret = e2.getTarget() or exists(AccessPath ap, Property target | - LibraryFlow::libraryFlow(_, _, _, _, ap, _) and + LibraryFlow::libraryFlowSummary(_, _, _, _, ap, _) and ap.contains(ret.getContent()) and target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and overridesOrImplementsSourceDecl(target, ret) @@ -337,7 +449,42 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ) } -Type getCSharpType(DotNet::Type t) { +/** + * Holds if `e` is an expression that adds `src` to array `a`. + * + * `postUpdate` indicates whether the store targets a post-update node. + */ +private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { + // Direct assignment, `a[i] = src` + exists(AssignableDefinition def | + a = def.getTargetAccess().(ArrayWrite).getQualifier() and + src = def.getSource() and + e = def.getExpr() and + postUpdate = true + ) + or + // Array initializer, `new [] { src }` + src = a.(ArrayInitializer).getAnElement() and + e = a and + postUpdate = false + or + // Member initalizer, `new C { Array = { [i] = src } }` + exists(MemberInitializer mi | + mi = a.(ObjectInitializer).getAMemberInitializer() and + mi.getLValue() instanceof ArrayAccess and + mi.getRValue() = src and + e = a and + postUpdate = false + ) +} + +/** + * Holds if `e2` is an expression that reads an array element from + * from expresion `e1`. + */ +private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() } + +private Type getCSharpType(DotNet::Type t) { result = t or result.matchesHandle(t) @@ -363,6 +510,8 @@ private DataFlowType getANonTypeParameterSubType(DataFlowType t) { /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { + private import LibraryFlow + cached newtype TNode = TExprNode(ControlFlow::Nodes::ElementNode cfn) { @@ -388,13 +537,16 @@ private module Cached { } or TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { exists(Call call, CallableFlowSinkDelegateArg sink | - LibraryFlow::libraryFlow(call, _, _, sink, _, _) and + libraryFlowSummary(call, _, _, sink, _, _) and i = sink.getDelegateIndex() and j = sink.getDelegateParameterIndex() and call.getArgument(i).getAControlFlowNode() = cfn ) } or TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or + TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) { + cfn.getElement().(ObjectCreation).hasInitializer() + } or TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) { exists(Argument a, Type t | a = cfn.getElement() and @@ -406,7 +558,9 @@ private module Cached { t = any(TypeParameter tp | not tp.isValueType()) ) or - fieldOrPropertyAssign(_, _, _, cfn.getElement()) + fieldOrPropertyStore(_, _, _, cfn.getElement(), true) + or + arrayStore(_, _, cfn.getElement(), true) or exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla | upd = TExprPostUpdateNode(fla.getAControlFlowNode()) @@ -416,52 +570,56 @@ private module Cached { } or TLibraryCodeNode( ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, - CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, LibraryCodeNodeState state ) { - LibraryFlow::libraryFlow(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) and + ( + state = TLibraryCodeNodeAfterReadState(sourceAp.drop(_)) and + (sourceAp.length() > 1 or sinkAp.length() > 0 or preservesValue = false) + or + state = TLibraryCodeNodeBeforeStoreState(sinkAp.drop(_)) and + (sinkAp.length() > 1 or sourceAp.length() > 0 or preservesValue = false) + ) + } or + TParamsArgumentNode(ControlFlow::Node callCfn) { + callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode() } /** * This is the local flow predicate that is used as a building block in global - * data flow. It is a strict subset of the `localFlowStep` predicate, as it - * excludes SSA flow through instance fields. + * data flow. It excludes SSA flow through instance fields, as flow through fields + * is handled by the global data-flow library, but includes various other steps + * that are only relevant for global flow. */ cached predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - exists(Ssa::Definition def | - LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and - not LocalFlow::usesInstanceField(def) - ) - or - any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - LocalFlow::localFlowStepCil(nodeFrom, nodeTo) + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) or - exists(LibraryCodeNode n | n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) - or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) - ) + nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } /** - * This is the extension of the predicate `simpleLocalFlowStep` that is exposed - * as the `localFlowStep` predicate. It includes SSA flow through instance fields. + * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. */ cached - predicate extendedLocalFlowStep(Node nodeFrom, Node nodeTo) { + predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) + or exists(Ssa::Definition def | LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and LocalFlow::usesInstanceField(def) ) + or + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) and + not LocalFlow::excludeFromExposedRelations(nodeFrom) and + not LocalFlow::excludeFromExposedRelations(nodeTo) } /** @@ -477,7 +635,8 @@ private module Cached { cached newtype TContent = TFieldContent(Field f) { f = f.getSourceDeclaration() } or - TPropertyContent(Property p) { p = p.getSourceDeclaration() } + TPropertyContent(Property p) { p = p.getSourceDeclaration() } or + TElementContent() /** * Holds if data can flow from `node1` to `node2` via an assignment to @@ -485,17 +644,29 @@ private module Cached { */ cached predicate storeStepImpl(Node node1, Content c, Node node2) { - exists(StoreStepConfiguration x, ExprNode preNode2 | - preNode2 = node2.(PostUpdateNode).getPreUpdateNode() and - x.hasNodePath(node1, preNode2) and - fieldOrPropertyAssign(_, c, node1.asExpr(), preNode2.getExpr()) + exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | + x.hasNodePath(node1, node) and + if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 + | + fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate) + or + arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent ) or - exists(StoreStepConfiguration x | x.hasNodePath(node1, node2) | - fieldOrPropertyInit(node2.(ObjectCreationNode).getExpr(), c, node1.asExpr()) + exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn | + x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and + node2 = TParamsArgumentNode(callCfn) and + isParamsArg(_, arg, _) and + c instanceof ElementContent ) or - node2 = node1.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c)) + exists(Expr e | + e = node1.asExpr() and + node2.(YieldReturnNode).getYieldReturnStmt().getExpr() = e and + c instanceof ElementContent + ) + or + storeStepLibrary(node1, c, node2) } /** @@ -506,9 +677,38 @@ private module Cached { exists(ReadStepConfiguration x | x.hasNodePath(node1, node2) and fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + x.hasNodePath(node1, node2) and + arrayRead(node1.asExpr(), node2.asExpr()) and + c instanceof ElementContent + or + exists(ForeachStmt fs, Ssa::ExplicitDefinition def | + x + .hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(), + def.getControlFlowNode()) and + node2.(SsaDefinitionNode).getDefinition() = def and + c instanceof ElementContent + ) ) or - node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) + readStepLibrary(node1, c, node2) + } + + /** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ + cached + predicate clearsContent(Node n, Content c) { + fieldOrPropertyStore(_, c, _, n.asExpr(), true) + or + fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) + or + storeStepLibrary(n, c, _) and + not c instanceof ElementContent + or + clearsContentLibrary(n, c) } /** @@ -548,12 +748,57 @@ private module Cached { commonSubType(t, t2) ) } + + cached + predicate outRefReturnNode(Ssa::ExplicitDefinition def, OutRefReturnKind kind) { + exists(Parameter p | + def.isLiveOutRefParameterDefinition(p) and + kind.getPosition() = p.getPosition() + | + p.isOut() and kind instanceof OutReturnKind + or + p.isRef() and kind instanceof RefReturnKind + ) + } + + cached + predicate castNode(Node n) { + n.asExpr() instanceof Cast + or + n.(AssignableDefinitionNode).getDefinition() instanceof AssignableDefinitions::PatternDefinition + } + + /** Holds if `n` should be hidden from path explanations. */ + cached + predicate nodeIsHidden(Node n) { + exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | + def instanceof Ssa::PseudoDefinition + or + def instanceof Ssa::ImplicitEntryDefinition + or + def instanceof Ssa::ImplicitCallDefinition + ) + or + n instanceof YieldReturnNode + or + n instanceof ImplicitCapturedArgumentNode + or + n instanceof ImplicitDelegateOutNode + or + n instanceof ImplicitDelegateArgumentNode + or + n instanceof MallocNode + or + n instanceof LibraryCodeNode + or + n instanceof ParamsArgumentNode + } } import Cached /** An SSA definition, viewed as a node in a data flow graph. */ -class SsaDefinitionNode extends Node, TSsaDefinitionNode { +class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { Ssa::Definition def; SsaDefinitionNode() { this = TSsaDefinitionNode(def) } @@ -561,19 +806,23 @@ class SsaDefinitionNode extends Node, TSsaDefinitionNode { /** Gets the underlying SSA definition. */ Ssa::Definition getDefinition() { result = def } - override Callable getEnclosingCallable() { result = def.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = def.getEnclosingCallable() } - override Type getType() { result = def.getSourceVariable().getType() } + override Type getTypeImpl() { result = def.getSourceVariable().getType() } - override Location getLocation() { result = def.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { result = def.getControlFlowNode() } - override string toString() { + override Location getLocationImpl() { result = def.getLocation() } + + override string toStringImpl() { not explicitParameterNode(this, _) and result = def.toString() } } private module ParameterNodes { + abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { } + /** * Holds if definition node `node` is an entry definition for parameter `p`. */ @@ -585,7 +834,7 @@ private module ParameterNodes { * The value of an explicit parameter at function entry, viewed as a node in a data * flow graph. */ - class ExplicitParameterNode extends ParameterNode { + class ExplicitParameterNode extends ParameterNodeImpl { private DotNet::Parameter parameter; ExplicitParameterNode() { @@ -597,17 +846,19 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter } - override DotNet::Callable getEnclosingCallable() { result = parameter.getCallable() } + override DotNet::Callable getEnclosingCallableImpl() { result = parameter.getCallable() } - override DotNet::Type getType() { result = parameter.getType() } + override DotNet::Type getTypeImpl() { result = parameter.getType() } - override Location getLocation() { result = parameter.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = parameter.toString() } + override Location getLocationImpl() { result = parameter.getLocation() } + + override string toStringImpl() { result = parameter.toString() } } /** An implicit instance (`this`) parameter. */ - class InstanceParameterNode extends ParameterNode, TInstanceParameterNode { + class InstanceParameterNode extends ParameterNodeImpl, TInstanceParameterNode { private Callable callable; InstanceParameterNode() { this = TInstanceParameterNode(callable) } @@ -617,13 +868,15 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 } - override Callable getEnclosingCallable() { result = callable } + override Callable getEnclosingCallableImpl() { result = callable } - override Type getType() { result = callable.getDeclaringType() } + override Type getTypeImpl() { result = callable.getDeclaringType() } - override Location getLocation() { result = callable.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "this" } + override Location getLocationImpl() { result = callable.getLocation() } + + override string toStringImpl() { result = "this" } } module ImplicitCapturedParameterNodeImpl { @@ -776,7 +1029,7 @@ private module ArgumentNodes { * } } * ``` */ - class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode { + class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode { private LocalScopeVariable v; private ControlFlow::Nodes::ElementNode cfn; @@ -814,20 +1067,22 @@ private module ArgumentNodes { ) } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = v.getType() } + override Type getTypeImpl() { result = v.getType() } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[implicit argument] " + v } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[implicit argument] " + v } } /** * A node that corresponds to the value of an object creation (`new C()`) before * the constructor has run. */ - class MallocNode extends ArgumentNode, TMallocNode { + class MallocNode extends ArgumentNode, NodeImpl, TMallocNode { private ControlFlow::Nodes::ElementNode cfn; MallocNode() { this = TMallocNode(cfn) } @@ -837,15 +1092,15 @@ private module ArgumentNodes { pos = -1 } - override ControlFlow::Node getControlFlowNode() { result = cfn } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "malloc" } + override string toStringImpl() { result = "malloc" } } /** @@ -858,7 +1113,7 @@ private module ArgumentNodes { * * `x` is an implicit argument of the implicit call to `Foo`. */ - class ImplicitDelegateArgumentNode extends ArgumentNode, TImplicitDelegateArgumentNode { + class ImplicitDelegateArgumentNode extends ArgumentNode, NodeImpl, TImplicitDelegateArgumentNode { private ControlFlow::Node cfn; private int delegateIndex; private int parameterIndex; @@ -874,15 +1129,56 @@ private module ArgumentNodes { pos = parameterIndex } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { + override Type getTypeImpl() { result = this.getDelegateCall().getDelegateParameterType(parameterIndex) } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[implicit argument " + parameterIndex + "] " + cfn } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn } + } + + /** + * A data flow node that represents the implicit array creation in a call to a + * callable with a `params` parameter. For example, there is an implicit array + * creation `new [] { "a", "b", "c" }` in + * + * ```csharp + * void Foo(params string[] args) { ... } + * Foo("a", "b", "c"); + * ``` + * + * Note that array creations are not inserted when there is only one argument, + * and that argument is itself a compatible array, for example + * `Foo(new[] { "a", "b", "c" })`. + */ + class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode { + private ControlFlow::Node callCfn; + + ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) } + + private Parameter getParameter() { + callCfn = any(Call c | isParamsArg(c, _, result)).getAControlFlowNode() + } + + override predicate argumentOf(DataFlowCall call, int pos) { + callCfn = call.getControlFlowNode() and + pos = this.getParameter().getPosition() + } + + override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } + + override Type getTypeImpl() { result = this.getParameter().getType() } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = callCfn.getLocation() } + + override string toStringImpl() { result = "[implicit array creation] " + callCfn } } } @@ -920,16 +1216,7 @@ private module ReturnNodes { class OutRefReturnNode extends ReturnNode, SsaDefinitionNode { OutRefReturnKind kind; - OutRefReturnNode() { - exists(Parameter p | - this.getDefinition().(Ssa::ExplicitDefinition).isLiveOutRefParameterDefinition(p) and - kind.getPosition() = p.getPosition() - | - p.isOut() and kind instanceof OutReturnKind - or - p.isRef() and kind instanceof RefReturnKind - ) - } + OutRefReturnNode() { outRefReturnNode(this.getDefinition(), kind) } override ReturnKind getKind() { result = kind } } @@ -939,7 +1226,7 @@ private module ReturnNodes { * `yield return`s as stores into collections, i.e., there is flow from `e` * to `yield return e [e]`. */ - class YieldReturnNode extends ReturnNode, PostUpdateNode, TYieldReturnNode { + class YieldReturnNode extends ReturnNode, NodeImpl, TYieldReturnNode { private ControlFlow::Nodes::ElementNode cfn; private YieldReturnStmt yrs; @@ -949,15 +1236,15 @@ private module ReturnNodes { override YieldReturnKind getKind() { any() } - override ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } - override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() } + override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } - override Type getType() { result = yrs.getEnclosingCallable().getReturnType() } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Location getLocation() { result = yrs.getLocation() } + override Location getLocationImpl() { result = yrs.getLocation() } - override string toString() { result = yrs.toString() } + override string toStringImpl() { result = yrs.toString() } } /** @@ -1112,7 +1399,7 @@ private module OutNodes { * in a call to a library method. For example, the output from the implicit * call to `M` in `new Lazy(M)`. */ - class ImplicitDelegateOutNode extends OutNode, TImplicitDelegateOutNode { + class ImplicitDelegateOutNode extends OutNode, NodeImpl, TImplicitDelegateOutNode { private ControlFlow::Nodes::ElementNode cfn; private ControlFlow::Nodes::ElementNode call; @@ -1128,7 +1415,7 @@ private module OutNodes { call.getElement().(Call).getArgument(i) = cfn.getElement() } - override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) { result.getNode() = this and @@ -1141,17 +1428,17 @@ private module OutNodes { ) } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { + override Type getTypeImpl() { exists(ImplicitDelegateDataFlowCall c | c.getNode() = this | result = c.getDelegateReturnType() ) } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "[output] " + cfn } + override string toStringImpl() { result = "[output] " + cfn } } } @@ -1167,7 +1454,7 @@ module LibraryFlow { Call call, CallableFlowSource source, AccessPath sourceAp, Property p ) { exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration()) and + ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration(), _) and sourceAp = AccessPath::property(p0) and overridesOrImplementsSourceDecl(p, p0) and result = source.getSourceType(call) @@ -1199,7 +1486,7 @@ module LibraryFlow { Call call, CallableFlowSink sink, AccessPath sinkAp, Property p ) { exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration()) and + ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration(), _) and sinkAp = AccessPath::property(p0) and overridesOrImplementsSourceDecl(p, p0) and result = sink.getSinkType(call) @@ -1234,11 +1521,9 @@ module LibraryFlow { * `sourceAp` describes the contents of the source node that flows to the sink * (if any), and `sinkAp` describes the contents of the sink that it flows to * (if any). - * - * `preservesValue = false` implies that both `sourceAp` and `sinkAp` are empty. */ pragma[nomagic] - predicate libraryFlow( + predicate libraryFlowSummary( Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue ) { @@ -1249,9 +1534,8 @@ module LibraryFlow { sourceAp = AccessPath::empty() and sinkAp = AccessPath::empty() or - preservesValue = true and exists(AccessPath sourceAp0, AccessPath sinkAp0 | - ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c) and + ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c, preservesValue) and ( not sourceAp0 = AccessPath::property(_) and sourceAp = sourceAp0 @@ -1272,14 +1556,14 @@ module LibraryFlow { ) } - class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { + private class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { LibrarySourceConfiguration() { this = "LibrarySourceConfiguration" } override predicate candidate( Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exists(CallableFlowSource source | - libraryFlow(e2, source, _, _, _, _) and + libraryFlowSummary(e2, source, _, _, _, _) and e1 = source.getSource(e2) and scope = e2 and exactScope = false and @@ -1288,18 +1572,21 @@ module LibraryFlow { } } - class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { + private class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { LibrarySinkConfiguration() { this = "LibrarySinkConfiguration" } override predicate candidate( Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exists(CallableFlowSink sink | - libraryFlow(e1, _, _, sink, _, _) and + libraryFlowSummary(e1, _, _, sink, _, _) and e2 = sink.getSink(e1) and - scope = e1 and exactScope = false and - isSuccessor = false + if e2 instanceof ObjectOrCollectionInitializer + then scope = e2 and isSuccessor = true + else ( + scope = e1 and isSuccessor = false + ) ) } @@ -1308,7 +1595,7 @@ module LibraryFlow { boolean isSuccessor ) { exists(CallableFlowSinkArg sink | - libraryFlow(e, _, _, sink, _, _) and + libraryFlowSummary(e, _, _, sink, _, _) and scope = e and exactScope = false and isSuccessor = true and @@ -1317,122 +1604,325 @@ module LibraryFlow { ) } } + + newtype TLibraryCodeNodeState = + TLibraryCodeNodeAfterReadState(AccessPath ap) { ap.length() > 0 } or + TLibraryCodeNodeBeforeStoreState(AccessPath ap) { ap.length() > 0 } + + /** + * A state used to break up (complex) flow summaries for library code into atomic + * flow steps. For a flow summary with source access path `sourceAp` and sink + * access path `sinkAp`, the following states are used: + * + * - `TLibraryCodeNodeAfterReadState(AccessPath ap)`: this state represents + * that the head of `ap` has been read from, where `ap` is a suffix of + * `sourceAp`. + * - `TLibraryCodeNodeBeforeStoreState(AccessPath ap)`: this state represents + * that the head of `ap` is to be stored into next, where `ap` is a suffix of + * `sinkAp`. + * + * The state machine for flow summaries has no branching, hence from the entry + * state there is a unique path to the exit state. + */ + class LibraryCodeNodeState extends TLibraryCodeNodeState { + string toString() { + exists(AccessPath ap | + this = TLibraryCodeNodeAfterReadState(ap) and + result = "after read: " + ap + ) + or + exists(AccessPath ap | + this = TLibraryCodeNodeBeforeStoreState(ap) and + result = "before store: " + ap + ) + } + + /** Holds if this state represents the state after the last read. */ + predicate isLastReadState() { + this = TLibraryCodeNodeAfterReadState(any(AccessPath ap | ap.length() = 1)) + } + + /** Holds if this state represents the state before the first store. */ + predicate isFirstStoreState() { + this = TLibraryCodeNodeBeforeStoreState(any(AccessPath ap | ap.length() = 1)) + } + } + + /** + * Holds if `entry` is an entry node of kind `source` for the call `callCfn`, which + * targets a library callable with a flow summary. + */ + private predicate entry(Node entry, ControlFlow::Node callCfn, CallableFlowSource source) { + // The source is either an argument or a qualifier, for example + // `s` in `int.Parse(s)` + exists(LibrarySourceConfiguration x, Call call | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(source.getSource(call), entry.(ExprNode).getControlFlowNode(), _, callCfn) + ) + or + // The source is the output of a supplied delegate argument, for + // example the output of `Foo` in `new Lazy(Foo)` + exists(DataFlowCall call, int pos | + pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and + entry.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and + callCfn = call.getControlFlowNode() + ) + } + + /** + * Holds if `exit` is an exit node of kind `sink` for the call `callCfn`, which + * targets a library callable with a flow summary. + */ + private predicate exit(Node exit, ControlFlow::Node callCfn, CallableFlowSink sink) { + exists(LibrarySinkConfiguration x, Call call, ExprNode e | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) + | + // The sink is an ordinary return value, for example `int.Parse(s)` + sink instanceof CallableFlowSinkReturn and + exit = e + or + // The sink is a qualifier, for example `list` in `list.Add(x)` + sink instanceof CallableFlowSinkQualifier and + if e.getExpr() instanceof ObjectOrCollectionInitializer + then exit = e + else exit.(ExprPostUpdateNode).getPreUpdateNode() = e + ) + or + // The sink is an `out`/`ref` argument, for example `out i` in + // `int.TryParse(s, out i)` + exists(LibrarySinkConfiguration x, OutRefReturnKind k | + exit = + any(ParamOutNode out | + out.getCall(k).getControlFlowNode() = callCfn and + sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and + x.hasDefPath(_, callCfn, out.getDefinition(), _) + ) + ) + or + // The sink is a parameter of a supplied delegate argument, for example + // the parameter of `Foo` in `list.Select(Foo)`. + // + // This is implemented using a node that represents the implicit argument + // (`ImplicitDelegateArgumentNode`) of the implicit call + // (`ImplicitDelegateDataFlowCall`) to `Foo`. + exists( + DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex + | + sink = + any(CallableFlowSinkDelegateArg s | + delegateIndex = s.getDelegateIndex() and + parameterIndex = s.getDelegateParameterIndex() + ) and + exit = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and + dcall.isArgumentOf(call, delegateIndex) and + callCfn = call.getControlFlowNode() + ) + } + + /** + * Holds if there is a local step from `pred` to `succ`, which is synthesized + * from a library-code flow summary. + */ + predicate localStepLibrary(Node pred, Node succ, boolean preservesValue) { + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp + | + libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + | + // Simple flow summary without reads or stores + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + or + // Entry step for a complex summary with no reads and (1) multiple stores, or + // (2) at least one store and non-value-preservation + exists(LibraryCodeNodeState succState | + sourceAp.length() = 0 and + entry(pred, callCfn, source) and + succState.isFirstStoreState() and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + or + // Exit step for a complex summary with no stores and (1) multiple reads, or + // (2) at least one read and non-value-preservation + exists(LibraryCodeNodeState predState | + sinkAp.length() = 0 and + predState.isLastReadState() and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + exit(succ, callCfn, sink) + ) + ) + or + // Internal step for complex flow summaries with both reads and writes + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, LibraryCodeNodeState predState, + LibraryCodeNodeState succState + | + predState.isLastReadState() and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + succState.isFirstStoreState() and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + } + + /** + * Holds if there is a store of `pred` into content `c` of `succ`, which happens + * via library code. + */ + predicate setterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { + exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | + libraryFlowSummary(callCfn.getElement(), source, AccessPath::empty(), sink, + AccessPath::singleton(c), preservesValue) + | + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + ) + } + + /** + * Holds if data can flow from `pred` to `succ` via an assignment to + * content `c`, using library code. + */ + predicate storeStepLibrary(Node pred, Content c, Node succ) { + // Complex flow summary + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + LibraryCodeNodeState predState, AccessPath ap + | + predState = TLibraryCodeNodeBeforeStoreState(ap) and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + c = ap.getHead() + | + // More stores needed + exists(LibraryCodeNodeState succState | + succState = TLibraryCodeNodeBeforeStoreState(any(AccessPath succAp | succAp.getTail() = ap)) and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + or + // Last store + ap = sinkAp and + exit(succ, callCfn, sink) + ) + or + // Value-preserving setter + setterLibrary(pred, c, succ, true) + } + + /** + * Holds if there is a read of `c` from `pred` to `succ`, which happens via + * library code. + */ + predicate getterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { + exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | + libraryFlowSummary(callCfn.getElement(), source, AccessPath::singleton(c), sink, + AccessPath::empty(), preservesValue) and + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + ) + } + + /** + * Holds if data can flow from `pred` to `succ` via a read of content `c`, + * using library code. + */ + predicate readStepLibrary(Node pred, Content c, Node succ) { + // Complex flow summary + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + LibraryCodeNodeState succState, AccessPath ap + | + succState = TLibraryCodeNodeAfterReadState(ap) and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) and + c = ap.getHead() + | + // First read + ap = sourceAp and + entry(pred, callCfn, source) + or + // Subsequent reads + exists(LibraryCodeNodeState predState, AccessPath predAp | + predState = TLibraryCodeNodeAfterReadState(predAp) and + predAp.getTail() = ap and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) + ) + ) + or + // Value-preserving getter + getterLibrary(pred, c, succ, true) + } + + /** + * Holds if values stored inside content `c` are cleared at node `n`, as a result + * of calling a library method. + */ + predicate clearsContentLibrary(Node n, Content c) { + exists(LibraryTypeDataFlow ltdf, CallableFlowSource source, Call call | + ltdf.clearsContent(source, c, call.getTarget().getSourceDeclaration()) and + n.asExpr() = source.getSource(call) + ) + } +} + +/** Gets the type of content `c`. */ +pragma[noinline] +private DataFlowType getContentType(Content c) { + exists(Type t | result = Gvn::getGlobalValueNumber(t) | + t = c.(FieldContent).getField().getType() + or + t = c.(PropertyContent).getProperty().getType() + or + c instanceof ElementContent and + t instanceof ObjectType // we don't know what the actual element type is + ) } /** A data-flow node used to model flow through library code. */ -class LibraryCodeNode extends Node, TLibraryCodeNode { +class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { private ControlFlow::Node callCfn; private CallableFlowSource source; private AccessPath sourceAp; private CallableFlowSink sink; private AccessPath sinkAp; private boolean preservesValue; + private LibraryFlow::LibraryCodeNodeState state; LibraryCodeNode() { - this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue) + this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, state) } - /** Holds if this node is part of a value-preserving library step. */ - predicate preservesValue() { preservesValue = true } + override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } - /** - * Gets the predecessor of this library-code node. The head of `ap` describes - * the content that is read from when entering this node (if any). - */ - Node getPredecessor(AccessPath ap) { - ap = sourceAp and - ( - // The source is either an argument or a qualifier, for example - // `s` in `int.Parse(s)` - exists(LibraryFlow::LibrarySourceConfiguration x, Call call | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(source.getSource(call), result.(ExprNode).getControlFlowNode(), _, callCfn) - ) + override DataFlowType getDataFlowType() { + exists(AccessPath ap | + state = LibraryFlow::TLibraryCodeNodeAfterReadState(ap) and + if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true + then result = Gvn::getGlobalValueNumber(sink.getSinkType(callCfn.getElement())) + else result = getContentType(ap.getHead()) or - // The source is the output of a supplied delegate argument, for - // example the output of `Foo` in `new Lazy(Foo)` - exists(DataFlowCall call, int pos | - pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and - result.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and - callCfn = call.getControlFlowNode() - ) + state = LibraryFlow::TLibraryCodeNodeBeforeStoreState(ap) and + if sourceAp.length() = 0 and state.isFirstStoreState() and preservesValue = true + then result = Gvn::getGlobalValueNumber(source.getSourceType(callCfn.getElement())) + else result = getContentType(ap.getHead()) ) } - /** - * Gets the successor of this library-code node. The head of `ap` describes - * the content that is stored into when leaving this node (if any). - */ - Node getSuccessor(AccessPath ap) { - ap = sinkAp and - ( - exists(LibraryFlow::LibrarySinkConfiguration x, Call call, ExprNode e | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) - | - // The sink is an ordinary return value, for example `int.Parse(s)` - sink instanceof CallableFlowSinkReturn and - result = e - or - // The sink is a qualifier, for example `list` in `list.Add(x)` - sink instanceof CallableFlowSinkQualifier and - if sinkAp = AccessPath::empty() - then result = e - else result.(ExprPostUpdateNode).getPreUpdateNode() = e - ) - or - // The sink is an `out`/`ref` argument, for example `out i` in - // `int.TryParse(s, out i)` - exists(LibraryFlow::LibrarySinkConfiguration x, OutRefReturnKind k | - result = - any(ParamOutNode out | - out.getCall(k).getControlFlowNode() = callCfn and - sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and - x.hasDefPath(_, callCfn, out.getDefinition(), _) - ) - ) - or - // The sink is a parameter of a supplied delegate argument, for example - // the parameter of `Foo` in `list.Select(Foo)`. - // - // This is implemented using a node that represents the implicit argument - // (`ImplicitDelegateArgumentNode`) of the implicit call - // (`ImplicitDelegateDataFlowCall`) to `Foo`. - exists( - DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex - | - sink = - any(CallableFlowSinkDelegateArg s | - delegateIndex = s.getDelegateIndex() and - parameterIndex = s.getDelegateParameterIndex() - ) and - result = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and - dcall.isArgumentOf(call, delegateIndex) and - callCfn = call.getControlFlowNode() - ) - ) - } + override DotNet::Type getTypeImpl() { none() } - override Callable getEnclosingCallable() { result = callCfn.getEnclosingCallable() } + override ControlFlow::Node getControlFlowNodeImpl() { result = callCfn } - override DataFlowType getTypeBound() { - preservesValue = true and - sourceAp = AccessPath::empty() and - result = this.getPredecessor(_).getTypeBound() - or - result = sourceAp.getHead().getType() - or - preservesValue = false and - result = this.getSuccessor(_).getTypeBound() - } + override Location getLocationImpl() { result = callCfn.getLocation() } - override Location getLocation() { result = callCfn.getLocation() } - - override string toString() { result = "[library code] " + callCfn } + override string toStringImpl() { result = "[library code: " + state + "] " + callCfn } } /** A field or a property. */ -private class FieldOrProperty extends Assignable, Modifiable { +class FieldOrProperty extends Assignable, Modifiable { FieldOrProperty() { this instanceof Field or @@ -1516,12 +2006,14 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exactScope = false and - isSuccessor = false and - fieldOrPropertyAssign(scope, _, e1, e2) + fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot()) or exactScope = false and - isSuccessor = false and - fieldOrPropertyInit(e2, _, e1) and + arrayStore(scope, e1, e2, isSuccessor.booleanNot()) + or + exactScope = false and + isSuccessor = true and + isParamsArg(e2, e1, _) and scope = e2 } } @@ -1538,12 +2030,41 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration isSuccessor = true and fieldOrPropertyRead(e1, _, e2) and scope = e2 + or + exactScope = false and + isSuccessor = true and + arrayRead(e1, e2) and + scope = e2 + } + + override predicate candidateDef( + Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, + boolean isSuccessor + ) { + exists(ForeachStmt fs | + e = fs.getIterableExpr() and + defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = + fs.getVariableDeclExpr() and + isSuccessor = true + | + scope = fs and + exactScope = true + or + scope = fs.getIterableExpr() and + exactScope = false + or + scope = fs.getVariableDeclExpr() and + exactScope = false + ) } } predicate readStep = readStepImpl/3; -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets the type of `n` used for type pruning. */ +DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() } + +/** Gets a string representation of a `DataFlowType`. */ string ppReprType(DataFlowType t) { result = t.toString() } private class DataFlowNullType extends DataFlowType { @@ -1595,25 +2116,68 @@ abstract class PostUpdateNode extends Node { private module PostUpdateNodes { class ObjectCreationNode extends PostUpdateNode, ExprNode, TExprNode { - ObjectCreationNode() { exists(ObjectCreation oc | this = TExprNode(oc.getAControlFlowNode())) } + private ObjectCreation oc; - override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } + ObjectCreationNode() { this = TExprNode(oc.getAControlFlowNode()) } + + override Node getPreUpdateNode() { + exists(ControlFlow::Nodes::ElementNode cfn | this = TExprNode(cfn) | + result.(ObjectInitializerNode).getControlFlowNode() = cfn + or + not oc.hasInitializer() and + result.(MallocNode).getControlFlowNode() = cfn + ) + } } - class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + /** + * A node that represents the value of a newly created object after the object + * has been created, but before the object initializer has been executed. + * + * Such a node acts as both a post-update node for the `MallocNode`, as well as + * a pre-update node for the `ObjectCreationNode`. + */ + class ObjectInitializerNode extends PostUpdateNode, NodeImpl, TObjectInitializerNode { + private ObjectCreation oc; + private ControlFlow::Nodes::ElementNode cfn; + + ObjectInitializerNode() { + this = TObjectInitializerNode(cfn) and + cfn = oc.getAControlFlowNode() + } + + /** Gets the initializer to which this initializer node belongs. */ + ObjectOrCollectionInitializer getInitializer() { result = oc.getInitializer() } + + override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + + override DotNet::Type getTypeImpl() { result = oc.getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } + + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[pre-initializer] " + cfn } + } + + class ExprPostUpdateNode extends PostUpdateNode, NodeImpl, TExprPostUpdateNode { private ControlFlow::Nodes::ElementNode cfn; ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) } override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[post] " + cfn.toString() } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[post] " + cfn.toString() } } } @@ -1621,16 +2185,7 @@ private import PostUpdateNodes /** A node that performs a type cast. */ class CastNode extends Node { - CastNode() { - this.asExpr() instanceof Cast - or - this.(AssignableDefinitionNode).getDefinition() instanceof - AssignableDefinitions::PatternDefinition - or - readStep(_, _, this) - or - storeStep(this, _, _) - } + CastNode() { castNode(this) } } class DataFlowExpr = DotNet::Expr; @@ -1676,6 +2231,3 @@ int accessPathLimit() { result = 3 } * This predicate is only used for consistency checks. */ predicate isImmutableOrUnobservable(Node n) { none() } - -pragma[inline] -DataFlowType getErasedRepr(DataFlowType t) { result = t } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 328db073d6e..2b5661c2001 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -39,35 +39,37 @@ class Node extends TNode { /** Gets the type of this node. */ cached - DotNet::Type getType() { none() } - - /** INTERNAL: Do not use. Gets an upper bound on the type of this node. */ - cached - DataFlowType getTypeBound() { - Stages::DataFlowStage::forceCachingInSameStage() and - exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | - t0 = getCSharpType(this.getType()) - or - not exists(getCSharpType(this.getType())) and - t0 instanceof ObjectType - ) + final DotNet::Type getType() { + Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl() } /** Gets the enclosing callable of this node. */ cached - DataFlowCallable getEnclosingCallable() { none() } + final DataFlowCallable getEnclosingCallable() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(DataFlowCallable c | c = this.(NodeImpl).getEnclosingCallableImpl() | c) + } /** Gets the control flow node corresponding to this node, if any. */ cached - ControlFlow::Node getControlFlowNode() { none() } + final ControlFlow::Node getControlFlowNode() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(ControlFlow::Node n | n = this.(NodeImpl).getControlFlowNodeImpl() | n) + } /** Gets a textual representation of this node. */ cached - string toString() { none() } + final string toString() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).toStringImpl() + } /** Gets the location of this node. */ cached - Location getLocation() { none() } + final Location getLocation() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).getLocationImpl() + } /** * Holds if this element is at the specified location. @@ -108,31 +110,6 @@ class ExprNode extends Node { this = TExprNode(cfn) and result = cfn.getElement() } - - override DataFlowCallable getEnclosingCallable() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getExpr().getEnclosingCallable() - } - - override ControlFlow::Nodes::ElementNode getControlFlowNode() { - Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result) - } - - override DotNet::Type getType() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getType() - } - - override Location getLocation() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation() - } - - override string toString() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getControlFlowNode().toString() - or - this = TCilExprNode(_) and - result = "CIL expression" - } } /** @@ -188,15 +165,7 @@ AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) { result.getDefinition() = def } -/** - * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localFlowStep(Node nodeFrom, Node nodeTo) { - simpleLocalFlowStep(nodeFrom, nodeTo) - or - extendedLocalFlowStep(nodeFrom, nodeTo) -} +predicate localFlowStep = localFlowStepImpl/2; /** * Holds if data flows from `source` to `sink` in zero or more local @@ -242,7 +211,8 @@ class BarrierGuard extends Guard { } /** - * A reference contained in an object. This is either a field or a property. + * A reference contained in an object. This is either a field, a property, + * or an element in a collection. */ class Content extends TContent { /** Gets a textual representation of this content. */ @@ -252,10 +222,10 @@ class Content extends TContent { Location getLocation() { none() } /** Gets the type of the object containing this content. */ - DataFlowType getContainerType() { none() } + deprecated DataFlowType getContainerType() { none() } /** Gets the type of this content. */ - DataFlowType getType() { none() } + deprecated DataFlowType getType() { none() } } /** A reference to a field. */ @@ -271,11 +241,11 @@ class FieldContent extends Content, TFieldContent { override Location getLocation() { result = f.getLocation() } - override DataFlowType getContainerType() { + deprecated override DataFlowType getContainerType() { result = Gvn::getGlobalValueNumber(f.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } } /** A reference to a property. */ @@ -291,9 +261,16 @@ class PropertyContent extends Content, TPropertyContent { override Location getLocation() { result = p.getLocation() } - override DataFlowType getContainerType() { + deprecated override DataFlowType getContainerType() { result = Gvn::getGlobalValueNumber(p.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } +} + +/** A reference to an element in a collection. */ +class ElementContent extends Content, TElementContent { + override string toString() { result = "[]" } + + override Location getLocation() { result instanceof EmptyLocation } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index 56b2cdbccf5..d031b345308 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -36,7 +36,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { * context, if any. The call context records the *last* call required to * resolve the target, if any. Example: * - * ``` + * ```csharp * public int M(Func f, string x) { * return f(x); * } @@ -60,7 +60,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { * Note that only the *last* call required is taken into account, hence if * `M` above is redefined as follows: * - * ``` + * ```csharp * public int M(Func f, string x) { * return M2(f, x); * } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll index f80a2036aea..9eb296b6787 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll @@ -78,7 +78,7 @@ module Steps { * assumption. For example, there is flow from `0` on line 3 to `i` on line * 8 and from `1` on line 4 to `i` on line 12 in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); @@ -106,7 +106,7 @@ module Steps { * 8 (but not from `1` on line 4 to `i` on line 12 because `C` is virtual) * in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 93fe29c4619..228b064dc01 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -1,13 +1,17 @@ private import csharp private import TaintTrackingPublic +private import DataFlowImplCommon +private import semmle.code.csharp.Caching private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.commons.ComparisonTest -private import semmle.code.csharp.frameworks.JsonNET private import cil private import dotnet +// import `TaintedMember` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.JsonNET +private import semmle.code.csharp.frameworks.WCF /** * Holds if `node` should be a barrier in all global taint flow configurations @@ -15,15 +19,7 @@ private import dotnet */ predicate defaultTaintBarrier(DataFlow::Node node) { none() } -/** - * Holds if the additional step from `src` to `sink` should be included in all - * global taint flow configurations. - */ -predicate defaultAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - localAdditionalTaintStep(pred, succ) - or - succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) -} +deprecated predicate localAdditionalTaintStep = defaultAdditionalTaintStep/2; private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { result = node.asParameter() or @@ -34,9 +30,6 @@ private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node node asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) } -/** Gets the qualifier of element access `ea`. */ -private Expr getElementAccessQualifier(ElementAccess ea) { result = ea.getQualifier() } - private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } @@ -45,28 +38,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) { exactScope = false and ( - // Taint from assigned value to element qualifier (`x[i] = 0`) - exists(AssignExpr ae | - e1 = ae.getRValue() and - e2.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) and - scope = ae and - isSuccessor = false - ) - or - // Taint from array initializer - e1 = e2.(ArrayCreation).getInitializer().getAnElement() and - scope = e2 and - isSuccessor = false - or - // Taint from object initializer - exists(ElementInitializer ei | - ei = e2.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and - e1 = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key) - scope = e2 and - isSuccessor = false - ) - or - // Taint from element qualifier e1 = e2.(ElementAccess).getQualifier() and scope = e2 and isSuccessor = true @@ -126,60 +97,77 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) ) } +} - override predicate candidateDef( - Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - // Taint from `foreach` expression - exists(ForeachStmt fs | - e = fs.getIterableExpr() and - defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = - fs.getVariableDeclExpr() and - isSuccessor = true - | - scope = fs and - exactScope = true - or - scope = fs.getIterableExpr() and - exactScope = false - or - scope = fs.getVariableDeclExpr() and - exactScope = false - ) - } +private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + Stages::DataFlowStage::forceCachingInSameStage() and + any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + localTaintStepCil(nodeFrom, nodeTo) } cached -module Cached { - private import semmle.code.csharp.Caching +private module Cached { + private import LibraryFlow + /** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ cached - predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - Stages::DataFlowStage::forceCachingInSameStage() and - any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + predicate localTaintStepImpl(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Ordinary data flow + DataFlow::localFlowStep(nodeFrom, nodeTo) or - nodeFrom = nodeTo.(YieldReturnNode).getPreUpdateNode() + localTaintStepCommon(nodeFrom, nodeTo) or - localTaintStepCil(nodeFrom, nodeTo) + not LocalFlow::excludeFromExposedRelations(nodeFrom) and + not LocalFlow::excludeFromExposedRelations(nodeTo) and + ( + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + or + // Taint collection by adding a tainted element + exists(DataFlow::ElementContent c | + storeStep(nodeFrom, c, nodeTo) + or + setterLibrary(nodeFrom, c, nodeTo, false) + ) + or + exists(DataFlow::Content c | + readStep(nodeFrom, c, nodeTo) + or + getterLibrary(nodeFrom, c, nodeTo, false) + | + // Taint members + c = any(TaintedMember m).(FieldOrProperty).getContent() + or + // Read from a tainted collection + c = TElementContent() + ) + ) + } + + /** + * Holds if the additional step from `nodeFrom` to `nodeTo` should be included + * in all global taint flow configurations. + */ + cached + predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + localTaintStepCommon(nodeFrom, nodeTo) or // Taint members - exists(Access access | - access = nodeTo.asExpr() and - access.getTarget() instanceof TaintedMember - | - access.(FieldRead).getQualifier() = nodeFrom.asExpr() - or - access.(PropertyRead).getQualifier() = nodeFrom.asExpr() - ) + readStep(nodeFrom, any(TaintedMember m).(FieldOrProperty).getContent(), nodeTo) or - exists(LibraryCodeNode n | not n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) - or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) - ) + // Although flow through collections is modelled precisely using stores/reads, we still + // allow flow out of a _tainted_ collection. This is needed in order to support taint- + // tracking configurations where the source is a collection + readStep(nodeFrom, TElementContent(), nodeTo) + or + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + or + nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll index eda33f2fcd9..6e4ba538a40 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll @@ -18,13 +18,4 @@ predicate localExprTaint(Expr e1, Expr e2) { /** A member (property or field) that is tainted if its containing object is tainted. */ abstract class TaintedMember extends AssignableMember { } -/** - * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Ordinary data flow - DataFlow::localFlowStep(nodeFrom, nodeTo) - or - localAdditionalTaintStep(nodeFrom, nodeTo) -} +predicate localTaintStep = localTaintStepImpl/2; diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll index 3e74eb4ff45..925ee3e9744 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll @@ -30,6 +30,26 @@ class DispatchCall extends Internal::TDispatchCall { /** Gets a dynamic (run-time) target of this call, if any. */ RuntimeCallable getADynamicTarget() { result = Internal::getADynamicTarget(this) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext() { Internal::mayBenefitFromCallContext(this) } + + /** + * Gets a dynamic (run-time) target of this call in call context `ctx`, if any. + * + * This predicate is restricted to calls for which `mayBenefitFromCallContext()` + * holds. + */ + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = Internal::getADynamicTargetInCallContext(this, ctx) + } } /** Internal implementation details. */ @@ -40,6 +60,7 @@ private module Internal { private import semmle.code.csharp.dataflow.internal.Steps private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Reflection + private import semmle.code.csharp.dataflow.internal.BaseSSA cached private module Cached { @@ -90,6 +111,16 @@ private module Internal { RuntimeCallable getADynamicTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getADynamicTarget() } + + cached + predicate mayBenefitFromCallContext(DispatchMethodOrAccessorCall dc) { + dc.mayBenefitFromCallContext(_, _) + } + + cached + RuntimeCallable getADynamicTargetInCallContext(DispatchMethodOrAccessorCall dc, DispatchCall ctx) { + result = dc.getADynamicTargetInCallContext(ctx) + } } import Cached @@ -190,6 +221,17 @@ private module Internal { abstract RuntimeCallable getADynamicTarget(); } + /** A non-constructed overridable callable. */ + private class NonConstructedOverridableCallable extends OverridableCallable { + NonConstructedOverridableCallable() { not this instanceof ConstructedMethod } + + OverridableCallable getAConstructingCallableOrSelf() { + result = this + or + result = this.(UnboundGenericMethod).getAConstructedGeneric() + } + } + pragma[noinline] private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) { exists(oc.getAnOverrider(t)) @@ -223,12 +265,13 @@ private module Internal { private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) { hasOverrider(_, t) and ( - exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) | - t = t0 + exists(Type t0, Type t1 | + t0 = getAPossibleType(call.getQualifier(), false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 or - Unification::subsumes(t0, t) - or - t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType() + Unification::subsumes(t1, t) ) or constrainedTypeParameterQualifierTypeSubsumes(t, @@ -249,15 +292,257 @@ private module Internal { abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl { pragma[nomagic] - predicate hasQualifierTypeInherited(SourceDeclarationType t) { - t = getAPossibleType(this.getQualifier(), _).getSourceDeclaration() - } + predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) } pragma[nomagic] predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) { hasQualifierTypeOverridden0(t, this) and hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext(Callable c, int i) { + 1 < strictcount(this.getADynamicTarget().getSourceDeclaration()) and + c = this.getCall().getEnclosingCallable().getSourceDeclaration() and + ( + exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p | + this.getQualifier() = BaseSsa::getARead(pdef, p) and + p.getPosition() = i and + c.getAParameter() = p and + not p.isParams() + ) + or + i = -1 and + this.getQualifier() instanceof ThisAccess + ) + } + + /** + * Holds if the call `ctx` might act as a context that improves the set of + * dispatch targets of this call, depending on the type of the `i`th argument + * of `ctx`. + */ + pragma[nomagic] + private predicate relevantContext(DispatchCall ctx, int i) { + this.mayBenefitFromCallContext(ctx.getADynamicTarget().getSourceDeclaration(), i) + } + + /** + * Holds if the argument of `ctx`, which is passed for the parameter that is + * accessed in the qualifier of this call, has type `t` and `ctx` is a relevant + * call context. + */ + private predicate contextArgHasType(DispatchCall ctx, Type t, boolean isExact) { + exists(Expr arg, int i | + this.relevantContext(ctx, i) and + t = getAPossibleType(arg, isExact) + | + ctx.getArgument(i) = arg + or + ctx.getQualifier() = arg and + i = -1 + ) + } + + pragma[nomagic] + private Callable getASubsumedStaticTarget0(Type t) { + exists(Callable staticTarget, Type declType | + staticTarget = this.getAStaticTarget() and + declType = staticTarget.getDeclaringType() and + result = staticTarget.getSourceDeclaration() and + Unification::subsumes(declType, t) + ) + } + + /** + * Gets a callable whose source declaration matches the source declaration of + * some static target `target`, and whose declaring type is subsumed by the + * declaring type of `target`. + */ + pragma[nomagic] + private Callable getASubsumedStaticTarget() { + result = this.getAStaticTarget() + or + result.getSourceDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType()) + } + + /** + * Gets a callable inherited by (or defined in) the qualifier type of this + * call that overrides (or equals) a static target of this call. + * + * Example: + * + * ```csharp + * class A + * { + * public virtual void M() { } + * } + * + * class B : A + * { + * public override void M() { } + * } + * + * class C : B { } + * + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 14, 16, and 18, + * but the methods inherited by the actual qualifier types are `A.M`, + * `B.M`, and `B.M`, respectively. + */ + private RuntimeCallable getAViableInherited() { + exists(NonConstructedOverridableCallable c, Type t | this.hasQualifierTypeInherited(t) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c.getInherited(t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + /** + * Gets a callable that is defined in a subtype of the qualifier type of this + * call, and which overrides a static target of this call. + * + * Example: + * + * ```csharp + * class A + * { + * public virtual void M() { } + * } + * + * class B : A + * { + * public override void M() { } + * } + * + * class C : B + * { + * public override void M() { } + * } + * + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 16, 18, and 20, + * but the methods overriding the static targets in subtypes of the actual + * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. + */ + private RuntimeCallable getAViableOverrider() { + exists(ValueOrRefType t, NonConstructedOverridableCallable c | + this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and + result = c.getAnOverrider(t) + ) + } + + override RuntimeCallable getADynamicTarget() { + result = getAViableInherited() + or + result = getAViableOverrider() + or + // Simple case: target method cannot be overridden + result = getAStaticTarget() and + not result instanceof OverridableCallable + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext0(ValueOrRefType t) { + this.contextArgHasType(_, t, _) and + result = this.getADynamicTarget() + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext1( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableInheritedInCallContext0(t) and + result = c.getInherited(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext(DispatchCall ctx) { + exists(Type t, NonConstructedOverridableCallable c | this.contextArgHasType(ctx, t, _) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = this.getAViableInheritedInCallContext1(c, t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext0( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableOverrider() and + this.contextArgHasType(_, _, false) and + result = c.getAnOverrider(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext1( + NonConstructedOverridableCallable c, DispatchCall ctx + ) { + exists(ValueOrRefType t | + result = this.getAViableOverriderInCallContext0(c, t) and + exists(Type t0, Type t1 | + this.contextArgHasType(ctx, t0, false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 + or + Unification::subsumes(t1, t) + ) + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) { + exists(NonConstructedOverridableCallable c | + result = this.getAViableOverriderInCallContext1(c, ctx) and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() + ) + } + + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = this.getAViableInheritedInCallContext(ctx) + or + result = this.getAViableOverriderInCallContext(ctx) + } } private class DynamicFieldOrProperty extends Assignable { @@ -386,6 +671,8 @@ private module Internal { .getQualifier() or this = any(DispatchCallImpl c).getQualifier() + or + this = any(DispatchCallImpl c).getArgument(_) } Source getASource() { stepTC(this, result) } @@ -430,109 +717,8 @@ private module Internal { override Expr getQualifier() { result = getCall().getQualifier() } override Method getAStaticTarget() { result = getCall().getTarget() } - - override RuntimeMethod getADynamicTarget() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target method cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableMethod - } - - /** - * Gets the (unique) instance method inherited by (or defined in) the - * qualifier type of this call that overrides (or equals) the static - * target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 14, 16, and 18, - * but the methods inherited by the actual qualifier types are `A.M`, - * `B.M`, and `B.M`, respectively. - */ - private RuntimeInstanceMethod getViableInherited() { - exists(NonConstructedOverridableMethod m, SourceDeclarationType t | - this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and - this.hasQualifierTypeInherited(t) - | - result = m.getInherited(t) - or - t instanceof TypeParameter and - result = m - ) - } - - /** - * Gets an instance method that is defined in a subtype of the qualifier - * type of this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { - * public override void M() { } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 16, 18, and 20, - * but the methods overriding the static targets in subtypes of the actual - * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. - */ - private RuntimeInstanceMethod getAViableOverrider() { - exists(ValueOrRefType t, NonConstructedOverridableMethod m | - this.hasQualifierTypeOverridden(t, m.getAConstructingMethodOrSelf()) and - result = m.getAnOverrider(t) - ) - } } - /** A non-constructed overridable method. */ - private class NonConstructedOverridableMethod extends OverridableMethod, NonConstructedMethod { } - /** * A call to an accessor. * @@ -549,7 +735,7 @@ private module Internal { override Accessor getAStaticTarget() { result = getCall().getTarget() } override RuntimeAccessor getADynamicTarget() { - result = getADynamicTargetCandidate() and + result = DispatchMethodOrAccessorCall.super.getADynamicTarget() and // Calls to accessors may have `dynamic` expression arguments, // so we need to check that the types match forall(Type argumentType, int i | hasDynamicArg(i, argumentType) | @@ -557,16 +743,6 @@ private module Internal { ) } - private RuntimeAccessor getADynamicTargetCandidate() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target accessor cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableAccessor - } - private predicate hasDynamicArg(int i, Type argumentType) { exists(Expr argument | argument = getArgument(i) and @@ -574,91 +750,6 @@ private module Internal { argumentType = getAPossibleType(argument, _) ) } - - /** - * Gets the (unique) accessor inherited by (or defined in) the qualifier - * type of this call that overrides (or equals) the static target of this - * call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 14, 16, and 18, - * but the accessors inherited by the actual qualifier types are `A.get_P`, - * `B.get_P`, and `B.get_P`, respectively. - */ - private RuntimeAccessor getViableInherited() { - exists(OverridableAccessor a, SourceDeclarationType t | - this.getAStaticTarget() = a and - this.hasQualifierTypeInherited(t) and - result = a.getInherited(t) - ) - } - - /** - * Gets an accessor that is defined in a subtype of the qualifier type of - * this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { - * public override int P { get => 2; } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 16, 18, and 20, - * but the accessors overriding the static targets in subtypes of the actual - * qualifier types are `B.get_P` and `C.get_P`, `C.get_P`, and none, - * respectively. - */ - private RuntimeAccessor getAViableOverrider() { - exists(ValueOrRefType t, OverridableAccessor a | - this.hasQualifierTypeOverridden(t, a) and - result = a.getAnOverrider(t) - ) - } } /** A reflection-based call or a call using dynamic types. */ @@ -686,22 +777,25 @@ private module Internal { * For reflection/dynamic calls, unless the type of the qualifier is exact, * all subtypes of the qualifier type must be considered relevant. Example: * - * ``` - * class A { - * public void M() { Console.WriteLine("A"); } + * ```csharp + * class A + * { + * public void M() { Console.WriteLine("A"); } * } * - * class B : A { - * new public void M() { Console.WriteLine("B"); } + * class B : A + * { + * new public void M() { Console.WriteLine("B"); } * } * - * class C { - * void InvokeMDyn(A x) { ((dynamic) x).M(); } + * class C + * { + * void InvokeMDyn(A x) { ((dynamic) x).M(); } * - * void CallM() { - * InvokeMDyn(new A()); // prints "A" - * InvokeMDyn(new B()); // prints "B" - * } + * void CallM() { + * InvokeMDyn(new A()); // prints "A" + * InvokeMDyn(new B()); // prints "B" + * } * } * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll index e8c717b8e09..cfb8c89f7bb 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -38,7 +38,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -76,7 +76,7 @@ class OverridableCallable extends Callable { * * Note that this is generally *not* equivalent with * - * ``` + * ```ql * result = getAnImplementor() * or * result = getAnImplementor().(OverridableCallable).getAnOverrider+()` @@ -84,7 +84,7 @@ class OverridableCallable extends Callable { * * as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } @@ -118,7 +118,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * class C1 { public virtual void M() { } } * * class C2 : C1 { public override void M() { } } @@ -134,10 +134,9 @@ class OverridableCallable extends Callable { * - `C2.M = C2.M.getInherited(C2)`, and * - `C2.M = C2.M.getInherited(C3)`. */ - Callable getInherited(SourceDeclarationType t) { - exists(Callable sourceDecl | result = this.getInherited2(t, sourceDecl) | - hasSourceDeclarationCallable(t, sourceDecl) - ) + Callable getInherited(ValueOrRefType t) { + result = this.getInherited1(t) and + t.hasCallable(result) } private Callable getInherited0(ValueOrRefType t) { @@ -150,19 +149,11 @@ class OverridableCallable extends Callable { exists(ValueOrRefType mid | result = this.getInherited0(mid) | t = mid.getASubType()) } - private Callable getInherited1(SourceDeclarationType t) { - exists(ValueOrRefType t0 | result = getInherited0(t0) | t = t0.getSourceDeclaration()) + private Callable getInherited1(ValueOrRefType t) { + result = getInherited0(t) or // An interface implementation - exists(ValueOrRefType s | - result = getAnImplementorSubType(s) and - t = s.getSourceDeclaration() - ) - } - - private Callable getInherited2(SourceDeclarationType t, Callable sourceDecl) { - result = this.getInherited1(t) and - sourceDecl = result.getSourceDeclaration() + result = getAnImplementorSubType(t) } pragma[noinline] @@ -218,11 +209,6 @@ class OverridableCallable extends Callable { } } -pragma[noinline] -private predicate hasSourceDeclarationCallable(ValueOrRefType t, Callable sourceDecl) { - exists(Callable c | t.hasCallable(c) | sourceDecl = c.getSourceDeclaration()) -} - /** An overridable method. */ class OverridableMethod extends Method, OverridableCallable { override Method getAnOverrider() { result = Method.super.getAnOverrider() } @@ -231,7 +217,7 @@ class OverridableMethod extends Method, OverridableCallable { override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() } - override Method getInherited(SourceDeclarationType t) { + override Method getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } @@ -278,7 +264,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { ) } - override Accessor getInherited(SourceDeclarationType t) { + override Accessor getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index 842c374ecd1..a935886f635 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -51,7 +51,7 @@ private module AccessImpl { /** * A `this` access, for example `this` on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -64,7 +64,7 @@ private module AccessImpl { * Note that a `this` access may be implicit, for example the implicit `this` * qualifier on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -83,7 +83,7 @@ class ThisAccess extends Access, @this_access_expr { /** * A `base` access, for example `base` on line 2 in * - * ``` + * ```csharp * public override void Dispose() { * base.Dispose(); * ... @@ -211,7 +211,7 @@ class LocalScopeVariableWrite extends LocalScopeVariableAccess, VariableWrite { /** * An access to a parameter, for example the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -227,7 +227,7 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr { * An access to a parameter that reads the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -245,7 +245,7 @@ class ParameterRead extends ParameterAccess, LocalScopeVariableRead { * An access to a parameter that updates the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * p = 1; * return p; @@ -257,7 +257,7 @@ class ParameterWrite extends ParameterAccess, VariableWrite { } /** * An access to a local variable, for example the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -279,7 +279,7 @@ class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_acce * An access to a local variable that reads the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -298,7 +298,7 @@ class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead { * An access to a local variable that updates the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * int x; * x = -p; @@ -311,7 +311,7 @@ class LocalVariableWrite extends LocalVariableAccess, VariableWrite { } /** * An access to a field, for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -331,7 +331,7 @@ class FieldAccess extends AssignableMemberAccess, VariableAccess, @field_access_ * An access to a field that reads the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -347,7 +347,7 @@ class FieldRead extends FieldAccess, VariableRead { } * An access to a field that updates the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -362,7 +362,7 @@ class FieldWrite extends FieldAccess, VariableWrite { } /** * An access to a member (field), for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * const int F = 0; * @@ -399,7 +399,7 @@ library class PropertyAccessExpr extends Expr, @property_access_expr { /** * An access to a property, for example the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -417,7 +417,7 @@ class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr { * An access to a property that reads the underlying value, for example * the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -437,7 +437,7 @@ class PropertyRead extends PropertyAccess, AssignableRead { * An access to a property that updates the underlying value, for example the * access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -453,7 +453,7 @@ class PropertyWrite extends PropertyAccess, AssignableWrite { } * An access to a trivial property - a property with a default getter and * setter. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -471,7 +471,7 @@ class TrivialPropertyAccess extends PropertyAccess { * An access to a virtual property - a property that is virtual or defined in * an interface. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * virtual int P { get; private set; } * @@ -534,7 +534,7 @@ library class IndexerAccessExpr extends Expr, @indexer_access_expr { /** * An access to an indexer, for example the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -556,7 +556,7 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess * An access to an indexer that reads the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -576,7 +576,7 @@ class IndexerRead extends IndexerAccess, ElementRead { * An access to an indexer that updates the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -592,7 +592,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * An access to a virtual indexer - an indexer that is virtual or defined in * an interface. For example, the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public virtual string this[int i] { ... } * @@ -600,6 +600,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * return c[0]; * } * } + * ``` */ class VirtualIndexerAccess extends IndexerAccess { VirtualIndexerAccess() { targetIsOverridableOrImplementable() } @@ -620,7 +621,7 @@ library class EventAccessExpr extends Expr, @event_access_expr { * An access to an event, for example the accesses to `Click` on lines * 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -641,7 +642,7 @@ class EventAccess extends AssignableMemberAccess, EventAccessExpr { * An access to an event that reads the underlying value, for example the * accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -660,7 +661,7 @@ class EventRead extends EventAccess, AssignableRead { } * An access to an event that updates the underlying value, for example the * access to `Click` on line 7 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -678,7 +679,7 @@ class EventWrite extends EventAccess, AssignableWrite { } * An access to a virtual event - an event that is virtual or defined in * an interface. For example, the accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -708,7 +709,7 @@ class CallableAccess extends Access, @method_access_expr { /** * An access to a method, for example the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * bool Filter(string s) { ... } * @@ -731,7 +732,7 @@ class MethodAccess extends MemberAccess, CallableAccess { /** * An access to a local function, for example the access to `Filter` on line 4 in * - * ``` + * ```csharp * class C { * public IEnumerable DoFilter(IEnumerable list) { * bool Filter(string s) { ... }; @@ -755,7 +756,7 @@ class LocalFunctionAccess extends CallableAccess { * An access to a virtual method - a method that is virtual or defined in * an interface. For example, the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * public virtual bool Filter(string s) { ... } * @@ -774,7 +775,7 @@ class VirtualMethodAccess extends MethodAccess { /** * An access to a type, for example the access to `C` on line 3 in * - * ``` + * ```csharp * class C { * public Type GetCType() { * return typeof(C); @@ -791,7 +792,7 @@ class TypeAccess extends MemberAccess, @type_access_expr { /** * An access to an array, for example the access to `args` on line 3 in * - * ``` + * ```csharp * public int FirstOrNegative(params int[] args) { * return args.Length > 0 * ? args[0] @@ -812,7 +813,7 @@ class ArrayAccess extends ElementAccess, @array_access_expr { * An access to an array that reads the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public string Get(string[] a, int i) { * return a[i]; * } @@ -824,7 +825,7 @@ class ArrayRead extends ArrayAccess, ElementRead { } * An access to an array that updates the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public void Set(string[] a, int i, string s) { * a[i] = s; * } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll index fe1a131e46c..9bfeffaeda2 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll @@ -192,7 +192,7 @@ class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr { /** * An event addition, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -213,7 +213,7 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr { /** * An event removal, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index 9e451781c54..7f17ef40297 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -22,7 +22,7 @@ class Call extends DotNet::Call, Expr, @call { * Gets the static (compile-time) target of this call. For example, the * static target of `x.M()` on line 9 is `A.M` in * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -65,7 +65,7 @@ class Call extends DotNet::Call, Expr, @call { * on line 5, `o` is not an argument for `M1`'s `args` parameter, while * `new object[] { o }` on line 6 is, in * - * ``` + * ```csharp * class C { * void M1(params object[] args) { } * @@ -143,7 +143,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getTarget()`, this predicate takes reflection/dynamic based calls, * virtual dispatch, and delegate calls into account. Example: * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -188,7 +188,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getArgument()`, this predicate takes reflection based calls and named * arguments into account. Example: * - * ``` + * ```csharp * class A { * virtual void M(int first, int second) { } * @@ -261,7 +261,7 @@ class Call extends DotNet::Call, Expr, @call { * of the arguments on lines 4 and 5, respectively, are valid for the parameter * `args` on line 1 in * - * ``` + * ```csharp * void M(params object[] args) { ... } * * void CallM(object[] os, string[] ss, string s) { @@ -280,7 +280,7 @@ private predicate isValidExplicitParamsType(Parameter p, Type t) { /** * A method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * void M() { } * @@ -310,7 +310,7 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca /** * A call to an extension method, for example lines 5 and 6 in * - * ``` + * ```csharp * static class A { * static void M(this int i) { } * @@ -341,7 +341,7 @@ class ExtensionMethodCall extends MethodCall { * happens to be an extension method, for example the calls on lines 6 and * 7 (but not line 5) in * - * ``` + * ```csharp * static class Extensions { * public static void Ext(int i) { } * @@ -363,7 +363,7 @@ class ExtensionMethodCall extends MethodCall { /** * A virtual method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * public virtual void M() { } * @@ -384,7 +384,7 @@ class VirtualMethodCall extends MethodCall { * A constructor initializer call, for example `base()` (line 6) and * `this(0)` (line 8) in * - * ``` + * ```csharp * class A * { * public A() { } @@ -417,7 +417,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `this` initializer, for example `this(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -431,7 +431,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `base` initializer, for example `base(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -450,7 +450,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * the initializer call `base()` on line 7 belongs to the constructor `B` * on line 6 in * - * ``` + * ```csharp * class A * { * public A() { } @@ -475,7 +475,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * A call to a user-defined operator, for example `this + other` * on line 7 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, A right) { * return left; @@ -499,7 +499,7 @@ class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr { * A call to a user-defined mutator operator, for example `a++` on * line 7 in * - * ``` + * ```csharp * class A { * public static A operator++(A a) { * return a; @@ -524,7 +524,7 @@ class MutatorOperatorCall extends OperatorCall { /** * A delegate call, for example `x()` on line 5 in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -581,7 +581,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { * Gets the delegate expression of this delegate call. For example, the * delegate expression of `X()` on line 5 is the access to the field `X` in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -613,7 +613,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { * A call to a property accessor, for example the call to `get_P` on * line 5 in * - * ``` + * ```csharp * class A { * int P { get { return 0; } } * @@ -644,7 +644,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr { * A call to an indexer accessor, for example the call to `get_Item` * (defined on line 3) on line 7 in * - * ``` + * ```csharp * class A { * string this[int i] { * get { return i.ToString(); } @@ -679,7 +679,7 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr { * A call to an event accessor, for example the call to `add_Click` * (defined on line 5) on line 12 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -722,7 +722,7 @@ class EventCall extends AccessorCall, EventAccessExpr { /** * A call to a local function, for example the call `Fac(n)` on line 6 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll index f0aebc389d0..1d309b6e7c1 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll @@ -17,7 +17,7 @@ class ObjectOrCollectionInitializer extends Expr, @objectorcollection_init_expr /** * An object initializer, for example `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -34,7 +34,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * is a member initializer of the object initializer `{ X = 0, Y = 1 }` on * line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -52,7 +52,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * `Y = 1` is the second (`i = 1`) member initializer of the object initializer * `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -78,7 +78,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr /** * A member initializer, for example `X = 0` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -99,7 +99,7 @@ class MemberInitializer extends AssignExpr { /** * A collection initializer, for example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -111,7 +111,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * Gets an element initializer of this collection initializer, for example the * implicit call to `Add(0, "a")` on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -125,7 +125,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * example the second (`i = 1`) element initializer is the implicit call to * `Add(1, "b")` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -148,7 +148,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * An element initializer, for example the implicit call to `Add(0, "a")` * on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -162,7 +162,7 @@ class ElementInitializer extends MethodCall { /** * A constructor call, for example `new A()` on line 3 in * - * ``` + * ```csharp * class A { * public static A Create() { * return new A(); @@ -188,7 +188,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { * Gets the object initializer or collection initializer of this constructor * call, if any. For example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -210,7 +210,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { * An anonymous constructor call, for example * `new { First = x[0], Last = x[x.Length - 1] }` on line 2 in * - * ``` + * ```csharp * public IEnumerable FirstLast(IEnumerable list) { * return list.Select(x => new { First = x[0], Last = x[x.Length - 1] }). * Select(y => y.First + y.Last); @@ -245,7 +245,7 @@ class DelegateCreation extends Expr, @delegate_creation_expr { /** * An explicit delegate creation, for example `new D(M)` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -260,7 +260,7 @@ class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_crea /** * An implicit delegate creation, for example the access to `M` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -275,7 +275,7 @@ class ImplicitDelegateCreation extends DelegateCreation, @implicit_delegate_crea /** * An array initializer, for example `{ {0, 1}, {2, 3}, {4, 5} }` in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -288,7 +288,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets an element of this array initializer, for example `{0, 1}` on line * 2 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -302,7 +302,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets the `i`th element of this array initializer, for example the second * (`i = 1`) element is `{2, 3}` on line 3 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -335,7 +335,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets a dimension's length argument of this array creation, for * example `5` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ @@ -345,7 +345,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets the `i`th dimension's length argument of this array creation, for * example the second (`i = 1`) dimension's length is `10` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll index 6493bd0dabf..f2cf6b71e79 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll @@ -22,7 +22,7 @@ class DynamicExpr extends LateBindableExpr { * A constructor call where one of the arguments is a `dynamic` expression, for * example `new A(d)` on line 8 in * - * ``` + * ```csharp * class A { * A(int i) { } * @@ -48,7 +48,7 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation { * A method call where the qualifier or one of the arguments is a `dynamic` * expression, for example `M(d)` on line 8 in * - * ``` + * ```csharp * class A { * void M(int i) { } * @@ -72,7 +72,7 @@ class DynamicMethodCall extends DynamicExpr, MethodCall { * A call to a user-defined operator where one of the operands is a `dynamic` * expression, for example `this + d` on line 12 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, int right) { * return left; @@ -100,7 +100,7 @@ class DynamicOperatorCall extends DynamicExpr, OperatorCall { * A call to a user-defined mutator operator where the operand is a `dynamic` * expression, for example `d++` on line 20 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -147,7 +147,7 @@ class DynamicAccess extends DynamicExpr { * A member access where the qualifier is a `dynamic` expression, for example * `d.X` on line 24 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -193,7 +193,7 @@ class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, * An access to a dynamic member that reads the underlying value, for example * `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -220,7 +220,7 @@ class DynamicMemberRead extends DynamicMemberAccess, AssignableRead { } * An access to a dynamic member that updates the underlying value, for * example `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -259,7 +259,7 @@ class DynamicMember extends AssignableMember { * A call to an accessor where the qualifier is a `dynamic` expression, for * example `d.X` on line 20 and `d[0]` on line 25 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -315,7 +315,7 @@ class DynamicAccessorCall extends DynamicAccess { * An element access where the qualifier is a `dynamic` expression, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -344,7 +344,7 @@ class DynamicElementAccess extends DynamicAccess, ElementAccess, @dynamic_elemen * An access to a dynamic element that reads the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -367,7 +367,7 @@ class DynamicElementRead extends DynamicElementAccess, ElementRead { } * An access to a dynamic element that updates the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 72596c42abc..cf95a524350 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -125,7 +125,7 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr { /** * Gets the local variable being declared, if any. The only case where * no variable is declared is when a discard symbol is used, for example - * ``` + * ```csharp * if (int.TryParse(s, out var _)) * ... * ``` @@ -237,7 +237,7 @@ class TernaryOperation extends Operation, @ternary_op { } /** * A parenthesized expression, for example `(2 + 3)` in * - * ``` + * ```csharp * 4 * (2 + 3) * ``` */ @@ -291,7 +291,7 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) { /** * A pattern expression, for example `(_, false)` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -308,7 +308,7 @@ class PatternExpr extends Expr { * (transitively). For example, `_`, `false`, and `(_, false)` belong to the * pattern match `(_, false) => true` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -441,65 +441,6 @@ class IsExpr extends Expr, PatternMatch, @is_expr { override string toString() { result = "... is ..." } } -/** An `is` type expression, for example, `x is string` or `x is string s`. */ -deprecated class IsTypeExpr extends IsExpr { - TypeAccess typeAccess; - - IsTypeExpr() { typeAccess = this.getChild(1) } - - /** - * Gets the type being accessed in this `is` expression, for example `string` - * in `x is string`. - */ - Type getCheckedType() { result = typeAccess.getTarget() } - - /** - * Gets the type access in this `is` expression, for example `string` in - * `x is string`. - */ - TypeAccess getTypeAccess() { result = typeAccess } -} - -/** An `is` pattern expression, for example `x is string s`. */ -deprecated class IsPatternExpr extends IsExpr { - LocalVariableDeclExpr typeDecl; - - IsPatternExpr() { typeDecl = this.getChild(2) } - - /** - * Gets the local variable declaration in this `is` pattern expression. - * For example `string s` in `x is string s`. - */ - LocalVariableDeclExpr getVariableDeclExpr() { result = typeDecl } - - /** - * Gets the type being accessed in this `is` expression, for example `string` - * in `x is string`. - */ - Type getCheckedType() { result = getTypeAccess().getTarget() } - - /** - * Gets the type access in this `is` expression, for example `string` in - * `x is string`. - */ - TypeAccess getTypeAccess() { result = this.getChild(1) } -} - -/** - * An `is` constant expression, for example `x is 5`. - */ -deprecated class IsConstantExpr extends IsExpr { - ConstantPatternExpr constant; - - IsConstantExpr() { constant = this.getPattern() } - - /** Gets the constant expression, for example `5` in `x is 5`. */ - Expr getConstant() { result = constant } - - /** Gets the value of the constant, for example 5 in `x is 5`. */ - string getConstantValue() { result = constant.getValue() } -} - /** A `switch` expression or statement. */ class Switch extends ControlFlowElement, @switch { /** Gets the `i`th case of this `switch`. */ @@ -517,7 +458,7 @@ class Switch extends ControlFlowElement, @switch { /** * A `switch` expression, for example - * ``` + * ```csharp * (a,b) switch { * (false, false) => true, * _ => false @@ -603,7 +544,7 @@ class Cast extends Expr { * An implicit cast. For example, the implicit cast from `string` to `object` * on line 3 in * - * ``` + * ```csharp * class C { * void M1(object o) { } * void M2(string s) => M1(s); @@ -618,7 +559,7 @@ class ImplicitCast extends Cast { * An explicit cast. For example, the explicit cast from `object` to `string` * on line 2 in * - * ``` + * ```csharp * class C { * string M1(object o) => (string) o; * } @@ -689,7 +630,7 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr { * A pointer indirection operation, for example `*pn` on line 7, * `pa->M()` on line 13, and `cp[1]` on line 18 in * - * ``` + * ```csharp * struct A { * public void M() { } * @@ -726,7 +667,7 @@ class PointerIndirectionExpr extends UnaryOperation, @pointer_indirection_expr { /** * An address-of expression, for example `&n` on line 4 in * - * ``` + * ```csharp * class A { * unsafe int DirectDerefence() { * int n = 10; @@ -753,7 +694,7 @@ class AwaitExpr extends Expr, @await_expr { /** * A `nameof` expression, for example `nameof(s)` on line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -774,7 +715,7 @@ class NameOfExpr extends Expr, @nameof_expr { /** * An interpolated string, for example `$"Hello, {name}!"` on line 2 in * - * ``` + * ```csharp * void Hello(string name) { * Console.WriteLine($"Hello, {name}!"); * } @@ -922,8 +863,8 @@ private Expr getAnAssignOrForeachChild() { * An expression representing a tuple, for example * `(1, 2)` on line 2 or `(var x, var y)` on line 5 in * - * ``` - * class { + * ```csharp + * class C { * (int, int) F() => (1, 2); * * void M() { @@ -948,7 +889,7 @@ class TupleExpr extends Expr, @tuple_expr { /** * A reference expression, for example `ref a[i]` on line 2 in * - * ``` + * ```csharp * ref int GetElement(int[] a, int i) { * return ref a[i]; * } @@ -966,7 +907,7 @@ class RefExpr extends Expr, @ref_expr { /** * A discard expression, for example `_` in * - * ``` + * ```csharp * (var name, _, _) = GetDetails(); * ``` */ @@ -980,7 +921,7 @@ private class UnknownExpr extends Expr, @unknown_expr { /** * A range expression, used to create a `System.Range`. For example - * ``` + * ```csharp * 1..3 * 1..^1 * 3.. @@ -1014,7 +955,7 @@ class IndexExpr extends Expr, @index_expr { /** * A nullable warning suppression expression, for example `x!` in - * ``` + * ```csharp * string GetName() * { * string? x = ...; diff --git a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll index 95f039383df..81e7a5e42d5 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll @@ -53,7 +53,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { /** * A null-coalescing operation, for example `s ?? ""` on line 2 in * - * ``` + * ```csharp * string NonNullOrEmpty(string s) { * return s ?? ""; * } @@ -73,7 +73,7 @@ class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @terna * A conditional expression, for example `s != null ? s.Length : -1` * on line 2 in * - * ``` + * ```csharp * int LengthOrNegative(string s) { * return s != null ? s.Length : -1; * } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index b3c1ca9f9d3..b81b3669cde 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -111,12 +111,12 @@ module EntityFramework { c = this.getAConstructor() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false or c = this.getAConversionTo() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false } ConversionOperator getAConversionTo() { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll index 7fb51406e16..a3f9cbff073 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll @@ -173,7 +173,7 @@ class InvalidFormatString extends StringLiteral { } /** Provides a dataflow configuration for format strings. */ -private module FormatFlow { +module FormatFlow { private import semmle.code.csharp.dataflow.DataFlow private class FormatConfiguration extends DataFlow2::Configuration { @@ -186,12 +186,21 @@ private module FormatFlow { } } - predicate hasFlow(StringLiteral lit, Expr format) { - exists(DataFlow::Node n1, DataFlow::Node n2, FormatConfiguration conf | - n1.asExpr() = lit and n2.asExpr() = format - | - conf.hasFlow(n1, n2) - ) + query predicate nodes = DataFlow2::PathGraph::nodes/3; + + query predicate edges = DataFlow2::PathGraph::edges/2; + + class PathNode = DataFlow2::PathNode; + + /** + * Holds if there is flow from string literal `lit` to the format string in + * `call`. `litNode` and `formatNode` are the corresponding data-flow path + * nodes. + */ + predicate hasFlowPath(StringLiteral lit, PathNode litNode, FormatCall call, PathNode formatNode) { + litNode.getNode().asExpr() = lit and + formatNode.getNode().asExpr() = call.getFormatExpr() and + any(FormatConfiguration conf).hasFlowPath(litNode, formatNode) } } @@ -218,10 +227,12 @@ class FormatCall extends MethodCall { } /** + * DEPRECATED: Use `FormatFlow::hasFlowPath()` instead. + * * Gets a format string. Global data flow analysis is applied to retrieve all * sources that can reach this method call. */ - StringLiteral getAFormatSource() { FormatFlow::hasFlow(result, this.getFormatExpr()) } + deprecated StringLiteral getAFormatSource() { FormatFlow::hasFlowPath(result, _, this, _) } /** * Gets the number of supplied arguments (excluding the format string and format @@ -245,7 +256,7 @@ class FormatCall extends MethodCall { /** Gets a supplied argument that is not used in the format string `src`. */ int getAnUnusedArgument(ValidFormatString src) { result = this.getASuppliedArgument() and - src = this.getAFormatSource() and + FormatFlow::hasFlowPath(src, _, this, _) and not result = src.getAnInsert() } } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll index b439f958a01..1152a69e402 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -106,7 +106,7 @@ module JsonNET { private class SerializedMember extends TaintTracking::TaintedMember { SerializedMember() { // This member has a Json attribute - exists(Class attribute | attribute = this.(Attributable).getAnAttribute().getType() | + exists(Class attribute | attribute = this.getAnAttribute().getType() | attribute.hasName("JsonPropertyAttribute") or attribute.hasName("JsonDictionaryAttribute") @@ -214,7 +214,7 @@ module JsonNET { any(Operator op | op.getDeclaringType() = this.getABaseType*() and op.getReturnType() instanceof StringType ) and - source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and + source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and preservesValue = false or diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll index 093c8da9318..70f4c85138d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll @@ -360,12 +360,11 @@ class SystemStringClass extends StringType { result.getReturnType() instanceof StringType } - /** Gets a `Join(string, ...)` method. */ + /** Gets a `Join(...)` method. */ Method getJoinMethod() { result.getDeclaringType() = this and result.hasName("Join") and result.getNumberOfParameters() > 1 and - result.getParameter(0).getType() instanceof StringType and result.getReturnType() instanceof StringType } @@ -564,7 +563,7 @@ private EqualsMethod getInheritedEqualsMethod(ValueOrRefType t) { t.hasMethod(re * * Example: * - * ``` + * ```csharp * abstract class A : IEquatable { * public abstract bool Equals(T other); * public override bool Equals(object other) { return other != null && GetType() == other.GetType() && Equals((T)other); } @@ -653,7 +652,7 @@ private DisposeMethod getInheritedDisposeMethod(ValueOrRefType t) { t.hasMethod( * * Example: * - * ``` + * ```csharp * class A : IDisposable { * public void Dispose() { Dispose(true); } * public virtual void Dispose(bool disposing) { ... } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll index a9505388a92..655648d88c9 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll @@ -53,3 +53,17 @@ class OperationMethod extends Method { ) } } + +/** + * Data flow for WCF data contracts. + * + * Flow is defined from a WCF data contract object to any of its data member + * properties. This flow model only makes sense from a taint-tracking perspective + * (a tainted data contract object implies tainted data members). + */ +private class DataContractMember extends TaintTracking::TaintedMember { + DataContractMember() { + this.getAnAttribute() instanceof DataMemberAttribute and + this.getDeclaringType() instanceof DataContractClass + } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index cdcc9c2a37c..3ebd7028504 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -27,6 +27,14 @@ class MicrosoftAspNetCoreMvcViewFeatures extends Namespace { } } +/** The 'Microsoft.AspNetCore.Mvc.Rendering' namespace. */ +class MicrosoftAspNetCoreMvcRendering extends Namespace { + MicrosoftAspNetCoreMvcRendering() { + getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + hasName("Rendering") + } +} + /** An attribute whose type is in the `Microsoft.AspNetCore.Mvc` namespace. */ class MicrosoftAspNetCoreMvcAttribute extends Attribute { MicrosoftAspNetCoreMvcAttribute() { @@ -191,11 +199,11 @@ class MicrosoftAspNetCoreMvcController extends Class { } } -/** The `Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper` class. */ -class MicrosoftAspNetCoreMvcHtmlHelperClass extends Class { - MicrosoftAspNetCoreMvcHtmlHelperClass() { - getNamespace() instanceof MicrosoftAspNetCoreMvcViewFeatures and - hasName("HtmlHelper") +/** The `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper` interface. */ +class MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface extends Interface { + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface() { + getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and + hasName("IHtmlHelper") } /** Gets the `Raw` method. */ diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll index e932740cc02..aee0a1c8f7c 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll @@ -52,3 +52,13 @@ class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface { class SystemCollectionsICollectionInterface extends SystemCollectionsInterface { SystemCollectionsICollectionInterface() { this.hasName("ICollection") } } + +/** The `System.Collections.IList` interface. */ +class SystemCollectionsIListInterface extends SystemCollectionsInterface { + SystemCollectionsIListInterface() { this.hasName("IList") } +} + +/** The `System.Collections.IDictionary` interface. */ +class SystemCollectionsIDictionaryInterface extends SystemCollectionsInterface { + SystemCollectionsIDictionaryInterface() { this.hasName("IDictionary") } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll index 3160f82f2d4..a3616e57522 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -136,3 +136,16 @@ class SystemCollectionsGenericICollectionInterface extends SystemCollectionsGene /** Gets the `Add` method. */ Method getAddMethod() { result = this.getAMethod("Add") } } + +/** The `System.Collections.Generic.IList<>` interface. */ +class SystemCollectionsGenericIListInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIListInterface() { this.hasName("IList<>") } +} + +/** The `System.Collections.Generic.IDictionary` interface. */ +class SystemCollectionsGenericIDictionaryInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIDictionaryInterface() { + this.hasName("IDictionary<,>") and + this.getNumberOfTypeParameters() = 2 + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql deleted file mode 100644 index 1ed778b88ce..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id csharp/ir-sanity-check - */ - -import implementation.raw.IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll deleted file mode 100644 index ec6de78cfa4..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll +++ /dev/null @@ -1,6 +0,0 @@ -private import internal.TempVariableTagInternal -private import Imports::TempVariableTag - -class TempVariableTag extends TTempVariableTag { - string toString() { result = getTempVariableTagId(this) } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll deleted file mode 100644 index 0ee01a30ac3..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll deleted file mode 100644 index 0ee01a30ac3..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll deleted file mode 100644 index 0ee01a30ac3..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll deleted file mode 100644 index 4fbc0f30169..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll deleted file mode 100644 index 0ee01a30ac3..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll deleted file mode 100644 index 4dee687dabd..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll deleted file mode 100644 index 354a09f0f58..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -private import semmle.code.csharp.ir.internal.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll deleted file mode 100644 index badd48552a5..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll +++ /dev/null @@ -1,30 +0,0 @@ -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * Class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql deleted file mode 100644 index 8727f57d097..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Raw IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id csharp/raw-ir-sanity-check - */ - -import IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -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 Imports::Overlap - 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 a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * 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()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index b49dacc701b..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 3d200900445..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll deleted file mode 100644 index 9aa0d93de1f..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll deleted file mode 100644 index 3b716c201ac..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll deleted file mode 100644 index 421091e00d3..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import IRConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll deleted file mode 100644 index 9ab8de41259..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll deleted file mode 100644 index 05b119f6c5b..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll deleted file mode 100644 index 997185fb9f7..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll deleted file mode 100644 index a74b4bffbc4..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll deleted file mode 100644 index 2f24e6a4059..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Contains an abstract class that is the super class of the classes that deal with compiler generated calls. - */ - -import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase -private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, - TranslatedCompilerGeneratedElement { - final override string toString() { - result = "compiler generated call (" + generatedBy.toString() + ")" - } - - override Instruction getUnmodeledDefinitionInstruction() { - result = getTranslatedFunction(this.getFunction()).getUnmodeledDefinitionInstruction() - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index 8464941e0a7..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR -import semmle.code.csharp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll deleted file mode 100644 index badd48552a5..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll +++ /dev/null @@ -1,30 +0,0 @@ -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * Class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql deleted file mode 100644 index eee45030caf..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ssa-ir-sanity-check - */ - -import IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -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 Imports::Overlap - 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 a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * 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()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index 188c68483ad..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 3d200900445..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll deleted file mode 100644 index e7884ce20b6..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.IR as InputIR -import AliasConfiguration as Configuration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll deleted file mode 100644 index 0db2b956610..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll deleted file mode 100644 index 9aa0d93de1f..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll deleted file mode 100644 index 3b716c201ac..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll deleted file mode 100644 index 7d27b9aa92f..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import SSAConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll deleted file mode 100644 index 9ab8de41259..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll deleted file mode 100644 index 05b119f6c5b..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll deleted file mode 100644 index 997185fb9f7..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll deleted file mode 100644 index a74b4bffbc4..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll deleted file mode 100644 index 6ee403226bc..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll deleted file mode 100644 index 44ff1f110c1..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as OldIR -import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 43f303dd024..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id csharp/unaliased-ssa-sanity-check - */ - -import SSASanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll deleted file mode 100644 index 91d4124f558..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR -import semmle.code.csharp.ir.internal.IntegerConstant as Ints -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll deleted file mode 100644 index 555cb581d37..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index 1f9f8c40003..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR -import semmle.code.csharp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll deleted file mode 100644 index ac65c1f32bd..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll +++ /dev/null @@ -1,16 +0,0 @@ -private import csharp -private import semmle.code.csharp.ir.implementation.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.Util -private import IRCSharpLanguage as Language - -newtype TIRVariable = - TIRAutomaticUserVariable(LocalScopeVariable var, Callable callable) { - Construction::functionHasIR(callable) and - var.getCallable() = callable - } or - TIRTempVariable( - Callable callable, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - Construction::hasTempVariable(callable, ast, tag, type) - } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll index 635c59363f5..763fb46a4f1 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll @@ -14,6 +14,8 @@ module XSS { import semmle.code.csharp.security.dataflow.flowsinks.Html import semmle.code.csharp.security.dataflow.flowsinks.Remote import semmle.code.csharp.security.dataflow.flowsources.Remote + private import semmle.code.csharp.dataflow.DataFlow2 + private import semmle.code.csharp.dataflow.TaintTracking2 /** * Holds if there is tainted flow from `source` to `sink` that may lead to a @@ -24,7 +26,7 @@ module XSS { predicate xssFlow(XssNode source, XssNode sink, string message) { // standard taint-tracking exists( - TaintTrackingConfiguration c, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode + TaintTrackingConfiguration c, DataFlow2::PathNode sourceNode, DataFlow2::PathNode sinkNode | sourceNode = source.asDataFlowNode() and sinkNode = sink.asDataFlowNode() and @@ -46,7 +48,7 @@ module XSS { module PathGraph { query predicate edges(XssNode pred, XssNode succ) { - exists(DataFlow::PathNode a, DataFlow::PathNode b | DataFlow::PathGraph::edges(a, b) | + exists(DataFlow2::PathNode a, DataFlow2::PathNode b | DataFlow2::PathGraph::edges(a, b) | pred.asDataFlowNode() = a and succ.asDataFlowNode() = b ) @@ -57,7 +59,7 @@ module XSS { } private newtype TXssNode = - TXssDataFlowNode(DataFlow::PathNode node) or + TXssDataFlowNode(DataFlow2::PathNode node) or TXssAspNode(AspInlineMember m) /** @@ -73,7 +75,7 @@ module XSS { Location getLocation() { none() } /** Gets the data flow node corresponding to this node, if any. */ - DataFlow::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() } + DataFlow2::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() } /** Gets the ASP inline code element corresponding to this node, if any. */ AspInlineMember asAspInlineMember() { result = this.(XssAspNode).getAspInlineMember() } @@ -81,12 +83,12 @@ module XSS { /** A data flow node, viewed as an XSS flow node. */ class XssDataFlowNode extends TXssDataFlowNode, XssNode { - DataFlow::PathNode node; + DataFlow2::PathNode node; XssDataFlowNode() { this = TXssDataFlowNode(node) } /** Gets the data flow node corresponding to this node. */ - DataFlow::PathNode getDataFlowNode() { result = node } + DataFlow2::PathNode getDataFlowNode() { result = node } override string toString() { result = node.toString() } @@ -130,7 +132,7 @@ module XSS { /** * A taint-tracking configuration for cross-site scripting (XSS) vulnerabilities. */ - class TaintTrackingConfiguration extends TaintTracking::Configuration { + class TaintTrackingConfiguration extends TaintTracking2::Configuration { TaintTrackingConfiguration() { this = "XSSDataFlowConfiguration" } override predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll index 2363e24ffeb..97b81b6561e 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll @@ -176,13 +176,18 @@ class WebPageWriteLiteralToSink extends HtmlSink { abstract class AspNetCoreHtmlSink extends HtmlSink { } /** - * An expression that is used as an argument to `HtmlHelper.Raw`, typically in + * An expression that is used as an argument to `IHtmlHelper.Raw`, typically in * a `.cshtml` file. */ class MicrosoftAspNetCoreMvcHtmlHelperRawSink extends AspNetCoreHtmlSink { MicrosoftAspNetCoreMvcHtmlHelperRawSink() { - this.getExpr() = - any(MicrosoftAspNetCoreMvcHtmlHelperClass h).getRawMethod().getACall().getAnArgument() + exists(Call c, Callable target | + c.getTarget() = target and + target.hasName("Raw") and + target.getDeclaringType().getABaseType*() instanceof + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface and + this.getExpr() = c.getAnArgument() + ) } } diff --git a/csharp/ql/src/semmle/code/dotnet/Element.qll b/csharp/ql/src/semmle/code/dotnet/Element.qll index 9d8b35023aa..10a688d8ddd 100644 --- a/csharp/ql/src/semmle/code/dotnet/Element.qll +++ b/csharp/ql/src/semmle/code/dotnet/Element.qll @@ -50,7 +50,7 @@ class NamedElement extends Element, @dotnet_named_element { * Gets the fully qualified name of this element, for example the * fully qualified name of `M` on line 3 is `N.C.M` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } diff --git a/csharp/ql/src/semmle/code/dotnet/Generics.qll b/csharp/ql/src/semmle/code/dotnet/Generics.qll index f9b773f4536..1d4233f7250 100644 --- a/csharp/ql/src/semmle/code/dotnet/Generics.qll +++ b/csharp/ql/src/semmle/code/dotnet/Generics.qll @@ -13,7 +13,7 @@ abstract class UnboundGeneric extends Generic { /** Gets the `i`th type parameter, if any. */ abstract TypeParameter getTypeParameter(int i); - /** Gets a type parameter, if any. */ + /** Gets a type parameter. */ TypeParameter getATypeParameter() { result = getTypeParameter(_) } /** @@ -42,10 +42,13 @@ abstract class ConstructedGeneric extends Generic { /** Gets the `i`th type argument, if any. */ abstract Type getTypeArgument(int i); - /** Gets a type argument, if any. */ + /** Gets a type argument. */ Type getATypeArgument() { result = getTypeArgument(_) } - /** Gets the unbound generic declaration from which this declaration was constructed. */ + /** + * Gets the unbound generic declaration from which this declaration was + * constructed. + */ UnboundGeneric getUnboundGeneric() { none() } /** Gets the total number of type arguments. */ diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index ad622770b3c..f2aa2d4ac31 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -497,10 +497,6 @@ expr_flowstate(unique int id: @expr ref, int state: int ref); @generic = @type | @method | @local_function; -is_generic(unique int id: @generic ref); - -is_constructed(unique int id: @generic ref); - type_parameters( unique int id: @type_parameter ref, int index: int ref, diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index 23525a6a24e..c9c66d5fc7a 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -15479,28 +15479,6 @@ -is_generic -77320 - - -id -77320 - - - - - -is_constructed -358124 - - -id -358124 - - - - - type_parameters 84292 diff --git a/csharp/ql/test/library-tests/ir/ir/array.cs b/csharp/ql/test/experimental/ir/ir/array.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/array.cs rename to csharp/ql/test/experimental/ir/ir/array.cs diff --git a/csharp/ql/test/library-tests/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/assignop.cs rename to csharp/ql/test/experimental/ir/ir/assignop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/casts.cs b/csharp/ql/test/experimental/ir/ir/casts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/casts.cs rename to csharp/ql/test/experimental/ir/ir/casts.cs diff --git a/csharp/ql/test/library-tests/ir/ir/collections.cs b/csharp/ql/test/experimental/ir/ir/collections.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/collections.cs rename to csharp/ql/test/experimental/ir/ir/collections.cs diff --git a/csharp/ql/test/library-tests/ir/ir/constructor_init.cs b/csharp/ql/test/experimental/ir/ir/constructor_init.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/constructor_init.cs rename to csharp/ql/test/experimental/ir/ir/constructor_init.cs diff --git a/csharp/ql/test/library-tests/ir/ir/crement.cs b/csharp/ql/test/experimental/ir/ir/crement.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/crement.cs rename to csharp/ql/test/experimental/ir/ir/crement.cs diff --git a/csharp/ql/test/library-tests/ir/ir/delegates.cs b/csharp/ql/test/experimental/ir/ir/delegates.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/delegates.cs rename to csharp/ql/test/experimental/ir/ir/delegates.cs diff --git a/csharp/ql/test/library-tests/ir/ir/events.cs b/csharp/ql/test/experimental/ir/ir/events.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/events.cs rename to csharp/ql/test/experimental/ir/ir/events.cs diff --git a/csharp/ql/test/library-tests/ir/ir/foreach.cs b/csharp/ql/test/experimental/ir/ir/foreach.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/foreach.cs rename to csharp/ql/test/experimental/ir/ir/foreach.cs diff --git a/csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs b/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs rename to csharp/ql/test/experimental/ir/ir/func_with_param_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/experimental/ir/ir/indexers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/indexers.cs rename to csharp/ql/test/experimental/ir/ir/indexers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs b/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs rename to csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inoutref.cs b/csharp/ql/test/experimental/ir/ir/inoutref.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inoutref.cs rename to csharp/ql/test/experimental/ir/ir/inoutref.cs diff --git a/csharp/ql/test/library-tests/ir/ir/isexpr.cs b/csharp/ql/test/experimental/ir/ir/isexpr.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/isexpr.cs rename to csharp/ql/test/experimental/ir/ir/isexpr.cs diff --git a/csharp/ql/test/library-tests/ir/ir/jumps.cs b/csharp/ql/test/experimental/ir/ir/jumps.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/jumps.cs rename to csharp/ql/test/experimental/ir/ir/jumps.cs diff --git a/csharp/ql/test/library-tests/ir/ir/lock.cs b/csharp/ql/test/experimental/ir/ir/lock.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/lock.cs rename to csharp/ql/test/experimental/ir/ir/lock.cs diff --git a/csharp/ql/test/library-tests/ir/ir/obj_creation.cs b/csharp/ql/test/experimental/ir/ir/obj_creation.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/obj_creation.cs rename to csharp/ql/test/experimental/ir/ir/obj_creation.cs diff --git a/csharp/ql/test/library-tests/ir/ir/pointers.cs b/csharp/ql/test/experimental/ir/ir/pointers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/pointers.cs rename to csharp/ql/test/experimental/ir/ir/pointers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/prop.cs b/csharp/ql/test/experimental/ir/ir/prop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/prop.cs rename to csharp/ql/test/experimental/ir/ir/prop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected similarity index 64% rename from csharp/ql/test/library-tests/ir/ir/raw_ir.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir.expected index b95d27bd8e2..785f3872787 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir.expected @@ -3,8 +3,7 @@ array.cs: # 2| Block 0 # 2| v2_1(Void) = EnterFunction : # 2| mu2_2() = AliasedDefinition : -# 2| mu2_3() = UnmodeledDefinition : -# 2| r2_4(glval) = InitializeThis : +# 2| r2_3(glval) = InitializeThis : # 4| r4_1(glval) = VariableAddress[one_dim] : # 4| mu4_2(Int32[]) = Uninitialized[one_dim] : &:r4_1 # 4| r4_3(Int32) = Constant[0] : @@ -29,7 +28,7 @@ array.cs: # 6| r6_2(Int32[]) = ElementsAddress : r6_1 # 6| r6_3(Int32) = Constant[0] : # 6| r6_4(Int32[]) = PointerAdd[4] : r6_2, r6_3 -# 6| r6_5(Int32) = Load : &:r6_4, ~mu2_3 +# 6| r6_5(Int32) = Load : &:r6_4, ~m? # 6| r6_6(glval) = VariableAddress[one_dim] : # 6| r6_7(Int32[]) = ElementsAddress : r6_6 # 6| r6_8(Int32) = Constant[1] : @@ -48,222 +47,214 @@ array.cs: # 10| r10_2(glval) = VariableAddress[one_dim] : # 10| r10_3(Int32[]) = ElementsAddress : r10_2 # 10| r10_4(glval) = VariableAddress[i] : -# 10| r10_5(Int32) = Load : &:r10_4, ~mu2_3 +# 10| r10_5(Int32) = Load : &:r10_4, ~m? # 10| r10_6(Int32[]) = PointerAdd[4] : r10_3, r10_5 # 10| mu10_7(Int32) = Store : &:r10_6, r10_1 -# 2| v2_5(Void) = ReturnVoid : -# 2| v2_6(Void) = UnmodeledUse : mu* -# 2| v2_7(Void) = AliasedUse : ~mu2_3 -# 2| v2_8(Void) = ExitFunction : +# 2| v2_4(Void) = ReturnVoid : +# 2| v2_5(Void) = AliasedUse : ~m? +# 2| v2_6(Void) = ExitFunction : # 13| System.Void ArrayTest.twod_and_init_acc() # 13| Block 0 -# 13| v13_1(Void) = EnterFunction : -# 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = InitializeThis : -# 15| r15_1(glval) = VariableAddress[a] : -# 15| mu15_2(Int32[,]) = Uninitialized[a] : &:r15_1 -# 15| r15_3(Int32) = Constant[0] : -# 15| r15_4(glval) = PointerAdd[8] : r15_1, r15_3 -# 15| r15_5(Int32) = Constant[0] : -# 15| r15_6(glval) = PointerAdd[4] : r15_4, r15_5 -# 15| r15_7(Int32) = Constant[100] : -# 15| mu15_8(Int32) = Store : &:r15_6, r15_7 -# 15| r15_9(Int32) = Constant[1] : -# 15| r15_10(glval) = PointerAdd[4] : r15_4, r15_9 -# 15| r15_11(Int32) = Constant[101] : -# 15| mu15_12(Int32) = Store : &:r15_10, r15_11 -# 15| r15_13(Int32) = Constant[1] : -# 15| r15_14(glval) = PointerAdd[8] : r15_1, r15_13 -# 15| r15_15(Int32) = Constant[0] : -# 15| r15_16(glval) = PointerAdd[4] : r15_14, r15_15 -# 15| r15_17(Int32) = Constant[102] : -# 15| mu15_18(Int32) = Store : &:r15_16, r15_17 -# 15| r15_19(Int32) = Constant[1] : -# 15| r15_20(glval) = PointerAdd[4] : r15_14, r15_19 -# 15| r15_21(Int32) = Constant[103] : -# 15| mu15_22(Int32) = Store : &:r15_20, r15_21 -# 16| r16_1(glval) = VariableAddress[b] : -# 16| mu16_2(Int32[,]) = Uninitialized[b] : &:r16_1 -# 17| r17_1(glval) = VariableAddress[c] : -# 17| mu17_2(Int32[,]) = Uninitialized[c] : &:r17_1 -# 17| r17_3(Int32) = Constant[0] : -# 17| r17_4(glval) = PointerAdd[8] : r17_1, r17_3 -# 17| r17_5(Int32) = Constant[0] : -# 17| r17_6(glval) = PointerAdd[4] : r17_4, r17_5 -# 17| r17_7(Int32) = Constant[100] : -# 17| mu17_8(Int32) = Store : &:r17_6, r17_7 -# 17| r17_9(Int32) = Constant[1] : -# 17| r17_10(glval) = PointerAdd[4] : r17_4, r17_9 -# 17| r17_11(Int32) = Constant[101] : -# 17| mu17_12(Int32) = Store : &:r17_10, r17_11 -# 17| r17_13(Int32) = Constant[1] : -# 17| r17_14(glval) = PointerAdd[8] : r17_1, r17_13 -# 17| r17_15(Int32) = Constant[0] : -# 17| r17_16(glval) = PointerAdd[4] : r17_14, r17_15 -# 17| r17_17(Int32) = Constant[102] : -# 17| mu17_18(Int32) = Store : &:r17_16, r17_17 -# 17| r17_19(Int32) = Constant[1] : -# 17| r17_20(glval) = PointerAdd[4] : r17_14, r17_19 -# 17| r17_21(Int32) = Constant[103] : -# 17| mu17_22(Int32) = Store : &:r17_20, r17_21 -# 18| r18_1(glval) = VariableAddress[d] : -# 18| mu18_2(Int32[,]) = Uninitialized[d] : &:r18_1 -# 18| r18_3(Int32) = Constant[0] : -# 18| r18_4(glval) = PointerAdd[8] : r18_1, r18_3 -# 18| r18_5(Int32) = Constant[0] : -# 18| r18_6(glval) = PointerAdd[4] : r18_4, r18_5 -# 18| r18_7(Int32) = Constant[100] : -# 18| mu18_8(Int32) = Store : &:r18_6, r18_7 -# 18| r18_9(Int32) = Constant[1] : -# 18| r18_10(glval) = PointerAdd[4] : r18_4, r18_9 -# 18| r18_11(Int32) = Constant[101] : -# 18| mu18_12(Int32) = Store : &:r18_10, r18_11 -# 18| r18_13(Int32) = Constant[1] : -# 18| r18_14(glval) = PointerAdd[8] : r18_1, r18_13 -# 18| r18_15(Int32) = Constant[0] : -# 18| r18_16(glval) = PointerAdd[4] : r18_14, r18_15 -# 18| r18_17(Int32) = Constant[102] : -# 18| mu18_18(Int32) = Store : &:r18_16, r18_17 -# 18| r18_19(Int32) = Constant[1] : -# 18| r18_20(glval) = PointerAdd[4] : r18_14, r18_19 -# 18| r18_21(Int32) = Constant[103] : -# 18| mu18_22(Int32) = Store : &:r18_20, r18_21 -# 19| r19_1(glval) = VariableAddress[e] : -# 19| r19_2(glval) = VariableAddress[a] : -# 19| r19_3(Int32[,]) = Load : &:r19_2, ~mu13_3 -# 19| mu19_4(Int32[,]) = Store : &:r19_1, r19_3 -# 20| r20_1(Int32) = Constant[-1] : -# 20| r20_2(glval) = VariableAddress[e] : -# 20| r20_3(Int32[,]) = ElementsAddress : r20_2 -# 20| r20_4(Int32) = Constant[1] : -# 20| r20_5(Int32[,]) = PointerAdd[4] : r20_3, r20_4 -# 20| r20_6(Int32[]) = ElementsAddress : r20_5 -# 20| r20_7(Int32) = Constant[1] : -# 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 -# 20| mu20_9(Int32) = Store : &:r20_8, r20_1 -# 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = UnmodeledUse : mu* -# 13| v13_7(Void) = AliasedUse : ~mu13_3 -# 13| v13_8(Void) = ExitFunction : +# 13| v13_1(Void) = EnterFunction : +# 13| mu13_2() = AliasedDefinition : +# 13| r13_3(glval) = InitializeThis : +# 15| r15_1(glval) = VariableAddress[a] : +# 15| mu15_2(Int32[,]) = Uninitialized[a] : &:r15_1 +# 15| r15_3(Int32) = Constant[0] : +# 15| r15_4(glval) = PointerAdd[8] : r15_1, r15_3 +# 15| r15_5(Int32) = Constant[0] : +# 15| r15_6(glval) = PointerAdd[4] : r15_4, r15_5 +# 15| r15_7(Int32) = Constant[100] : +# 15| mu15_8(Int32) = Store : &:r15_6, r15_7 +# 15| r15_9(Int32) = Constant[1] : +# 15| r15_10(glval) = PointerAdd[4] : r15_4, r15_9 +# 15| r15_11(Int32) = Constant[101] : +# 15| mu15_12(Int32) = Store : &:r15_10, r15_11 +# 15| r15_13(Int32) = Constant[1] : +# 15| r15_14(glval) = PointerAdd[8] : r15_1, r15_13 +# 15| r15_15(Int32) = Constant[0] : +# 15| r15_16(glval) = PointerAdd[4] : r15_14, r15_15 +# 15| r15_17(Int32) = Constant[102] : +# 15| mu15_18(Int32) = Store : &:r15_16, r15_17 +# 15| r15_19(Int32) = Constant[1] : +# 15| r15_20(glval) = PointerAdd[4] : r15_14, r15_19 +# 15| r15_21(Int32) = Constant[103] : +# 15| mu15_22(Int32) = Store : &:r15_20, r15_21 +# 16| r16_1(glval) = VariableAddress[b] : +# 16| mu16_2(Int32[,]) = Uninitialized[b] : &:r16_1 +# 17| r17_1(glval) = VariableAddress[c] : +# 17| mu17_2(Int32[,]) = Uninitialized[c] : &:r17_1 +# 17| r17_3(Int32) = Constant[0] : +# 17| r17_4(glval) = PointerAdd[8] : r17_1, r17_3 +# 17| r17_5(Int32) = Constant[0] : +# 17| r17_6(glval) = PointerAdd[4] : r17_4, r17_5 +# 17| r17_7(Int32) = Constant[100] : +# 17| mu17_8(Int32) = Store : &:r17_6, r17_7 +# 17| r17_9(Int32) = Constant[1] : +# 17| r17_10(glval) = PointerAdd[4] : r17_4, r17_9 +# 17| r17_11(Int32) = Constant[101] : +# 17| mu17_12(Int32) = Store : &:r17_10, r17_11 +# 17| r17_13(Int32) = Constant[1] : +# 17| r17_14(glval) = PointerAdd[8] : r17_1, r17_13 +# 17| r17_15(Int32) = Constant[0] : +# 17| r17_16(glval) = PointerAdd[4] : r17_14, r17_15 +# 17| r17_17(Int32) = Constant[102] : +# 17| mu17_18(Int32) = Store : &:r17_16, r17_17 +# 17| r17_19(Int32) = Constant[1] : +# 17| r17_20(glval) = PointerAdd[4] : r17_14, r17_19 +# 17| r17_21(Int32) = Constant[103] : +# 17| mu17_22(Int32) = Store : &:r17_20, r17_21 +# 18| r18_1(glval) = VariableAddress[d] : +# 18| mu18_2(Int32[,]) = Uninitialized[d] : &:r18_1 +# 18| r18_3(Int32) = Constant[0] : +# 18| r18_4(glval) = PointerAdd[8] : r18_1, r18_3 +# 18| r18_5(Int32) = Constant[0] : +# 18| r18_6(glval) = PointerAdd[4] : r18_4, r18_5 +# 18| r18_7(Int32) = Constant[100] : +# 18| mu18_8(Int32) = Store : &:r18_6, r18_7 +# 18| r18_9(Int32) = Constant[1] : +# 18| r18_10(glval) = PointerAdd[4] : r18_4, r18_9 +# 18| r18_11(Int32) = Constant[101] : +# 18| mu18_12(Int32) = Store : &:r18_10, r18_11 +# 18| r18_13(Int32) = Constant[1] : +# 18| r18_14(glval) = PointerAdd[8] : r18_1, r18_13 +# 18| r18_15(Int32) = Constant[0] : +# 18| r18_16(glval) = PointerAdd[4] : r18_14, r18_15 +# 18| r18_17(Int32) = Constant[102] : +# 18| mu18_18(Int32) = Store : &:r18_16, r18_17 +# 18| r18_19(Int32) = Constant[1] : +# 18| r18_20(glval) = PointerAdd[4] : r18_14, r18_19 +# 18| r18_21(Int32) = Constant[103] : +# 18| mu18_22(Int32) = Store : &:r18_20, r18_21 +# 19| r19_1(glval) = VariableAddress[e] : +# 19| r19_2(glval) = VariableAddress[a] : +# 19| r19_3(Int32[,]) = Load : &:r19_2, ~m? +# 19| mu19_4(Int32[,]) = Store : &:r19_1, r19_3 +# 20| r20_1(Int32) = Constant[-1] : +# 20| r20_2(glval) = VariableAddress[e] : +# 20| r20_3(Int32[,]) = ElementsAddress : r20_2 +# 20| r20_4(Int32) = Constant[1] : +# 20| r20_5(Int32[,]) = PointerAdd[4] : r20_3, r20_4 +# 20| r20_6(Int32[]) = ElementsAddress : r20_5 +# 20| r20_7(Int32) = Constant[1] : +# 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 +# 20| mu20_9(Int32) = Store : &:r20_8, r20_1 +# 13| v13_4(Void) = ReturnVoid : +# 13| v13_5(Void) = AliasedUse : ~m? +# 13| v13_6(Void) = ExitFunction : assignop.cs: # 4| System.Void AssignOp.Main() # 4| Block 0 -# 4| v4_1(Void) = EnterFunction : -# 4| mu4_2() = AliasedDefinition : -# 4| mu4_3() = UnmodeledDefinition : -# 5| r5_1(glval) = VariableAddress[a] : -# 5| r5_2(Int32) = Constant[1] : -# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 6| r6_1(glval) = VariableAddress[c] : -# 6| r6_2(Int32) = Constant[1] : -# 6| mu6_3(Int32) = Store : &:r6_1, r6_2 -# 8| r8_1(glval) = VariableAddress[a] : -# 8| r8_2(Int32) = Load : &:r8_1, ~mu4_3 -# 8| r8_3(glval) = VariableAddress[c] : -# 8| r8_4(Int32) = Load : &:r8_3, ~mu4_3 -# 8| r8_5(Int32) = Add : r8_4, r8_2 -# 8| mu8_6(Int32) = Store : &:r8_3, r8_5 -# 9| r9_1(glval) = VariableAddress[a] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu4_3 -# 9| r9_3(glval) = VariableAddress[c] : -# 9| r9_4(Int32) = Load : &:r9_3, ~mu4_3 -# 9| r9_5(Int32) = Sub : r9_4, r9_2 -# 9| mu9_6(Int32) = Store : &:r9_3, r9_5 -# 10| r10_1(glval) = VariableAddress[a] : -# 10| r10_2(Int32) = Load : &:r10_1, ~mu4_3 -# 10| r10_3(glval) = VariableAddress[c] : -# 10| r10_4(Int32) = Load : &:r10_3, ~mu4_3 -# 10| r10_5(Int32) = Mul : r10_4, r10_2 -# 10| mu10_6(Int32) = Store : &:r10_3, r10_5 -# 11| r11_1(glval) = VariableAddress[a] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu4_3 -# 11| r11_3(glval) = VariableAddress[c] : -# 11| r11_4(Int32) = Load : &:r11_3, ~mu4_3 -# 11| r11_5(Int32) = Div : r11_4, r11_2 -# 11| mu11_6(Int32) = Store : &:r11_3, r11_5 -# 12| r12_1(glval) = VariableAddress[a] : -# 12| r12_2(Int32) = Load : &:r12_1, ~mu4_3 -# 12| r12_3(glval) = VariableAddress[c] : -# 12| r12_4(Int32) = Load : &:r12_3, ~mu4_3 -# 12| r12_5(Int32) = Rem : r12_4, r12_2 -# 12| mu12_6(Int32) = Store : &:r12_3, r12_5 -# 13| r13_1(Int32) = Constant[2] : -# 13| r13_2(glval) = VariableAddress[c] : -# 13| r13_3(Int32) = Load : &:r13_2, ~mu4_3 -# 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1 -# 13| mu13_5(Int32) = Store : &:r13_2, r13_4 -# 14| r14_1(Int32) = Constant[2] : -# 14| r14_2(glval) = VariableAddress[c] : -# 14| r14_3(Int32) = Load : &:r14_2, ~mu4_3 -# 14| r14_4(Int32) = ShiftRight : r14_3, r14_1 -# 14| mu14_5(Int32) = Store : &:r14_2, r14_4 -# 15| r15_1(Int32) = Constant[2] : -# 15| r15_2(glval) = VariableAddress[c] : -# 15| r15_3(Int32) = Load : &:r15_2, ~mu4_3 -# 15| r15_4(Int32) = BitAnd : r15_3, r15_1 -# 15| mu15_5(Int32) = Store : &:r15_2, r15_4 -# 16| r16_1(Int32) = Constant[2] : -# 16| r16_2(glval) = VariableAddress[c] : -# 16| r16_3(Int32) = Load : &:r16_2, ~mu4_3 -# 16| r16_4(Int32) = BitXor : r16_3, r16_1 -# 16| mu16_5(Int32) = Store : &:r16_2, r16_4 -# 17| r17_1(Int32) = Constant[2] : -# 17| r17_2(glval) = VariableAddress[c] : -# 17| r17_3(Int32) = Load : &:r17_2, ~mu4_3 -# 17| r17_4(Int32) = BitOr : r17_3, r17_1 -# 17| mu17_5(Int32) = Store : &:r17_2, r17_4 -# 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = UnmodeledUse : mu* -# 4| v4_6(Void) = AliasedUse : ~mu4_3 -# 4| v4_7(Void) = ExitFunction : +# 4| v4_1(Void) = EnterFunction : +# 4| mu4_2() = AliasedDefinition : +# 5| r5_1(glval) = VariableAddress[a] : +# 5| r5_2(Int32) = Constant[1] : +# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 +# 6| r6_1(glval) = VariableAddress[c] : +# 6| r6_2(Int32) = Constant[1] : +# 6| mu6_3(Int32) = Store : &:r6_1, r6_2 +# 8| r8_1(glval) = VariableAddress[a] : +# 8| r8_2(Int32) = Load : &:r8_1, ~m? +# 8| r8_3(glval) = VariableAddress[c] : +# 8| r8_4(Int32) = Load : &:r8_3, ~m? +# 8| r8_5(Int32) = Add : r8_4, r8_2 +# 8| mu8_6(Int32) = Store : &:r8_3, r8_5 +# 9| r9_1(glval) = VariableAddress[a] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(glval) = VariableAddress[c] : +# 9| r9_4(Int32) = Load : &:r9_3, ~m? +# 9| r9_5(Int32) = Sub : r9_4, r9_2 +# 9| mu9_6(Int32) = Store : &:r9_3, r9_5 +# 10| r10_1(glval) = VariableAddress[a] : +# 10| r10_2(Int32) = Load : &:r10_1, ~m? +# 10| r10_3(glval) = VariableAddress[c] : +# 10| r10_4(Int32) = Load : &:r10_3, ~m? +# 10| r10_5(Int32) = Mul : r10_4, r10_2 +# 10| mu10_6(Int32) = Store : &:r10_3, r10_5 +# 11| r11_1(glval) = VariableAddress[a] : +# 11| r11_2(Int32) = Load : &:r11_1, ~m? +# 11| r11_3(glval) = VariableAddress[c] : +# 11| r11_4(Int32) = Load : &:r11_3, ~m? +# 11| r11_5(Int32) = Div : r11_4, r11_2 +# 11| mu11_6(Int32) = Store : &:r11_3, r11_5 +# 12| r12_1(glval) = VariableAddress[a] : +# 12| r12_2(Int32) = Load : &:r12_1, ~m? +# 12| r12_3(glval) = VariableAddress[c] : +# 12| r12_4(Int32) = Load : &:r12_3, ~m? +# 12| r12_5(Int32) = Rem : r12_4, r12_2 +# 12| mu12_6(Int32) = Store : &:r12_3, r12_5 +# 13| r13_1(Int32) = Constant[2] : +# 13| r13_2(glval) = VariableAddress[c] : +# 13| r13_3(Int32) = Load : &:r13_2, ~m? +# 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1 +# 13| mu13_5(Int32) = Store : &:r13_2, r13_4 +# 14| r14_1(Int32) = Constant[2] : +# 14| r14_2(glval) = VariableAddress[c] : +# 14| r14_3(Int32) = Load : &:r14_2, ~m? +# 14| r14_4(Int32) = ShiftRight : r14_3, r14_1 +# 14| mu14_5(Int32) = Store : &:r14_2, r14_4 +# 15| r15_1(Int32) = Constant[2] : +# 15| r15_2(glval) = VariableAddress[c] : +# 15| r15_3(Int32) = Load : &:r15_2, ~m? +# 15| r15_4(Int32) = BitAnd : r15_3, r15_1 +# 15| mu15_5(Int32) = Store : &:r15_2, r15_4 +# 16| r16_1(Int32) = Constant[2] : +# 16| r16_2(glval) = VariableAddress[c] : +# 16| r16_3(Int32) = Load : &:r16_2, ~m? +# 16| r16_4(Int32) = BitXor : r16_3, r16_1 +# 16| mu16_5(Int32) = Store : &:r16_2, r16_4 +# 17| r17_1(Int32) = Constant[2] : +# 17| r17_2(glval) = VariableAddress[c] : +# 17| r17_3(Int32) = Load : &:r17_2, ~m? +# 17| r17_4(Int32) = BitOr : r17_3, r17_1 +# 17| mu17_5(Int32) = Store : &:r17_2, r17_4 +# 4| v4_3(Void) = ReturnVoid : +# 4| v4_4(Void) = AliasedUse : ~m? +# 4| v4_5(Void) = ExitFunction : casts.cs: # 11| System.Void Casts.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 13| r13_1(glval) = VariableAddress[Aobj] : # 13| r13_2(Casts_A) = NewObj : # 13| r13_3() = FunctionAddress[Casts_A] : # 13| v13_4(Void) = Call : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~mu11_3 +# 13| mu13_5() = ^CallSideEffect : ~m? # 13| mu13_6(Casts_A) = Store : &:r13_1, r13_2 # 14| r14_1(glval) = VariableAddress[bobjCE] : # 14| r14_2(glval) = VariableAddress[Aobj] : -# 14| r14_3(Casts_A) = Load : &:r14_2, ~mu11_3 +# 14| r14_3(Casts_A) = Load : &:r14_2, ~m? # 14| r14_4(Casts_B) = CheckedConvertOrThrow : r14_3 # 14| mu14_5(Casts_B) = Store : &:r14_1, r14_4 # 15| r15_1(glval) = VariableAddress[bobjAS] : # 15| r15_2(glval) = VariableAddress[Aobj] : -# 15| r15_3(Casts_A) = Load : &:r15_2, ~mu11_3 +# 15| r15_3(Casts_A) = Load : &:r15_2, ~m? # 15| r15_4(Casts_B) = CheckedConvertOrNull : r15_3 # 15| mu15_5(Casts_B) = Store : &:r15_1, r15_4 -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : collections.cs: # 11| System.Void Collections.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 13| r13_1(glval>) = VariableAddress[dict] : # 13| r13_2(Dictionary) = NewObj : # 13| r13_3() = FunctionAddress[Dictionary] : # 13| v13_4(Void) = Call : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~mu11_3 +# 13| mu13_5() = ^CallSideEffect : ~m? # 15| r15_1() = FunctionAddress[Add] : # 15| r15_2(Int32) = Constant[0] : # 15| r15_3(MyClass) = NewObj : # 15| r15_4() = FunctionAddress[MyClass] : # 15| v15_5(Void) = Call : func:r15_4, this:r15_3 -# 15| mu15_6() = ^CallSideEffect : ~mu11_3 +# 15| mu15_6() = ^CallSideEffect : ~m? # 15| r15_7(String) = StringConstant["Hello"] : # 15| r15_8(glval) = FieldAddress[a] : r15_3 # 15| mu15_9(String) = Store : &:r15_8, r15_7 @@ -271,13 +262,13 @@ collections.cs: # 15| r15_11(glval) = FieldAddress[b] : r15_3 # 15| mu15_12(String) = Store : &:r15_11, r15_10 # 15| v15_13(Void) = Call : func:r15_1, this:r13_2, 0:r15_2, 1:r15_3 -# 15| mu15_14() = ^CallSideEffect : ~mu11_3 +# 15| mu15_14() = ^CallSideEffect : ~m? # 16| r16_1() = FunctionAddress[Add] : # 16| r16_2(Int32) = Constant[1] : # 16| r16_3(MyClass) = NewObj : # 16| r16_4() = FunctionAddress[MyClass] : # 16| v16_5(Void) = Call : func:r16_4, this:r16_3 -# 16| mu16_6() = ^CallSideEffect : ~mu11_3 +# 16| mu16_6() = ^CallSideEffect : ~m? # 16| r16_7(String) = StringConstant["Foo"] : # 16| r16_8(glval) = FieldAddress[a] : r16_3 # 16| mu16_9(String) = Store : &:r16_8, r16_7 @@ -285,118 +276,106 @@ collections.cs: # 16| r16_11(glval) = FieldAddress[b] : r16_3 # 16| mu16_12(String) = Store : &:r16_11, r16_10 # 16| v16_13(Void) = Call : func:r16_1, this:r13_2, 0:r16_2, 1:r16_3 -# 16| mu16_14() = ^CallSideEffect : ~mu11_3 +# 16| mu16_14() = ^CallSideEffect : ~m? # 13| mu13_6(Dictionary) = Store : &:r13_1, r13_2 -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : constructor_init.cs: # 5| System.Void BaseClass..ctor() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = InitializeThis : -# 6| v6_1(Void) = NoOp : -# 5| v5_5(Void) = ReturnVoid : -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 5| r5_3(glval) = InitializeThis : +# 6| v6_1(Void) = NoOp : +# 5| v5_4(Void) = ReturnVoid : +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : # 9| System.Void BaseClass..ctor(System.Int32) # 9| Block 0 # 9| v9_1(Void) = EnterFunction : # 9| mu9_2() = AliasedDefinition : -# 9| mu9_3() = UnmodeledDefinition : -# 9| r9_4(glval) = InitializeThis : -# 9| r9_5(glval) = VariableAddress[i] : -# 9| mu9_6(Int32) = InitializeParameter[i] : &:r9_5 +# 9| r9_3(glval) = InitializeThis : +# 9| r9_4(glval) = VariableAddress[i] : +# 9| mu9_5(Int32) = InitializeParameter[i] : &:r9_4 # 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu9_3 -# 11| r11_3(BaseClass) = CopyValue : r9_4 +# 11| r11_2(Int32) = Load : &:r11_1, ~m? +# 11| r11_3(BaseClass) = CopyValue : r9_3 # 11| r11_4(glval) = FieldAddress[num] : r11_3 # 11| mu11_5(Int32) = Store : &:r11_4, r11_2 -# 9| v9_7(Void) = ReturnVoid : -# 9| v9_8(Void) = UnmodeledUse : mu* -# 9| v9_9(Void) = AliasedUse : ~mu9_3 -# 9| v9_10(Void) = ExitFunction : +# 9| v9_6(Void) = ReturnVoid : +# 9| v9_7(Void) = AliasedUse : ~m? +# 9| v9_8(Void) = ExitFunction : # 17| System.Void DerivedClass..ctor() # 17| Block 0 # 17| v17_1(Void) = EnterFunction : # 17| mu17_2() = AliasedDefinition : -# 17| mu17_3() = UnmodeledDefinition : -# 17| r17_4(glval) = InitializeThis : -# 17| r17_5(glval) = Convert[DerivedClass : BaseClass] : r17_4 -# 17| r17_6() = FunctionAddress[BaseClass] : -# 17| v17_7(Void) = Call : func:r17_6, this:r17_5 -# 17| mu17_8() = ^CallSideEffect : ~mu17_3 +# 17| r17_3(glval) = InitializeThis : +# 17| r17_4(glval) = Convert[DerivedClass : BaseClass] : r17_3 +# 17| r17_5() = FunctionAddress[BaseClass] : +# 17| v17_6(Void) = Call : func:r17_5, this:r17_4 +# 17| mu17_7() = ^CallSideEffect : ~m? # 18| v18_1(Void) = NoOp : -# 17| v17_9(Void) = ReturnVoid : -# 17| v17_10(Void) = UnmodeledUse : mu* -# 17| v17_11(Void) = AliasedUse : ~mu17_3 -# 17| v17_12(Void) = ExitFunction : +# 17| v17_8(Void) = ReturnVoid : +# 17| v17_9(Void) = AliasedUse : ~m? +# 17| v17_10(Void) = ExitFunction : # 21| System.Void DerivedClass..ctor(System.Int32) # 21| Block 0 # 21| v21_1(Void) = EnterFunction : # 21| mu21_2() = AliasedDefinition : -# 21| mu21_3() = UnmodeledDefinition : -# 21| r21_4(glval) = InitializeThis : -# 21| r21_5(glval) = VariableAddress[i] : -# 21| mu21_6(Int32) = InitializeParameter[i] : &:r21_5 -# 21| r21_7(glval) = Convert[DerivedClass : BaseClass] : r21_4 -# 21| r21_8() = FunctionAddress[BaseClass] : -# 21| r21_9(glval) = VariableAddress[i] : -# 21| r21_10(Int32) = Load : &:r21_9, ~mu21_3 -# 21| v21_11(Void) = Call : func:r21_8, this:r21_7, 0:r21_10 -# 21| mu21_12() = ^CallSideEffect : ~mu21_3 +# 21| r21_3(glval) = InitializeThis : +# 21| r21_4(glval) = VariableAddress[i] : +# 21| mu21_5(Int32) = InitializeParameter[i] : &:r21_4 +# 21| r21_6(glval) = Convert[DerivedClass : BaseClass] : r21_3 +# 21| r21_7() = FunctionAddress[BaseClass] : +# 21| r21_8(glval) = VariableAddress[i] : +# 21| r21_9(Int32) = Load : &:r21_8, ~m? +# 21| v21_10(Void) = Call : func:r21_7, this:r21_6, 0:r21_9 +# 21| mu21_11() = ^CallSideEffect : ~m? # 22| v22_1(Void) = NoOp : -# 21| v21_13(Void) = ReturnVoid : -# 21| v21_14(Void) = UnmodeledUse : mu* -# 21| v21_15(Void) = AliasedUse : ~mu21_3 -# 21| v21_16(Void) = ExitFunction : +# 21| v21_12(Void) = ReturnVoid : +# 21| v21_13(Void) = AliasedUse : ~m? +# 21| v21_14(Void) = ExitFunction : # 25| System.Void DerivedClass..ctor(System.Int32,System.Int32) # 25| Block 0 # 25| v25_1(Void) = EnterFunction : # 25| mu25_2() = AliasedDefinition : -# 25| mu25_3() = UnmodeledDefinition : -# 25| r25_4(glval) = InitializeThis : -# 25| r25_5(glval) = VariableAddress[i] : -# 25| mu25_6(Int32) = InitializeParameter[i] : &:r25_5 -# 25| r25_7(glval) = VariableAddress[j] : -# 25| mu25_8(Int32) = InitializeParameter[j] : &:r25_7 -# 25| r25_9() = FunctionAddress[DerivedClass] : -# 25| r25_10(glval) = VariableAddress[i] : -# 25| r25_11(Int32) = Load : &:r25_10, ~mu25_3 -# 25| v25_12(Void) = Call : func:r25_9, this:r25_4, 0:r25_11 -# 25| mu25_13() = ^CallSideEffect : ~mu25_3 +# 25| r25_3(glval) = InitializeThis : +# 25| r25_4(glval) = VariableAddress[i] : +# 25| mu25_5(Int32) = InitializeParameter[i] : &:r25_4 +# 25| r25_6(glval) = VariableAddress[j] : +# 25| mu25_7(Int32) = InitializeParameter[j] : &:r25_6 +# 25| r25_8() = FunctionAddress[DerivedClass] : +# 25| r25_9(glval) = VariableAddress[i] : +# 25| r25_10(Int32) = Load : &:r25_9, ~m? +# 25| v25_11(Void) = Call : func:r25_8, this:r25_3, 0:r25_10 +# 25| mu25_12() = ^CallSideEffect : ~m? # 26| v26_1(Void) = NoOp : -# 25| v25_14(Void) = ReturnVoid : -# 25| v25_15(Void) = UnmodeledUse : mu* -# 25| v25_16(Void) = AliasedUse : ~mu25_3 -# 25| v25_17(Void) = ExitFunction : +# 25| v25_13(Void) = ReturnVoid : +# 25| v25_14(Void) = AliasedUse : ~m? +# 25| v25_15(Void) = ExitFunction : # 29| System.Void DerivedClass.Main() # 29| Block 0 # 29| v29_1(Void) = EnterFunction : # 29| mu29_2() = AliasedDefinition : -# 29| mu29_3() = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[obj1] : # 31| r31_2(DerivedClass) = NewObj : # 31| r31_3() = FunctionAddress[DerivedClass] : # 31| v31_4(Void) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu29_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 31| mu31_6(DerivedClass) = Store : &:r31_1, r31_2 # 32| r32_1(glval) = VariableAddress[obj2] : # 32| r32_2(DerivedClass) = NewObj : # 32| r32_3() = FunctionAddress[DerivedClass] : # 32| r32_4(Int32) = Constant[1] : # 32| v32_5(Void) = Call : func:r32_3, this:r32_2, 0:r32_4 -# 32| mu32_6() = ^CallSideEffect : ~mu29_3 +# 32| mu32_6() = ^CallSideEffect : ~m? # 32| mu32_7(DerivedClass) = Store : &:r32_1, r32_2 # 33| r33_1(glval) = VariableAddress[obj3] : # 33| r33_2(DerivedClass) = NewObj : @@ -404,212 +383,194 @@ constructor_init.cs: # 33| r33_4(Int32) = Constant[1] : # 33| r33_5(Int32) = Constant[2] : # 33| v33_6(Void) = Call : func:r33_3, this:r33_2, 0:r33_4, 1:r33_5 -# 33| mu33_7() = ^CallSideEffect : ~mu29_3 +# 33| mu33_7() = ^CallSideEffect : ~m? # 33| mu33_8(DerivedClass) = Store : &:r33_1, r33_2 -# 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = UnmodeledUse : mu* -# 29| v29_6(Void) = AliasedUse : ~mu29_3 -# 29| v29_7(Void) = ExitFunction : +# 29| v29_3(Void) = ReturnVoid : +# 29| v29_4(Void) = AliasedUse : ~m? +# 29| v29_5(Void) = ExitFunction : crement.cs: # 3| System.Void CrementOpsTest.Main() # 3| Block 0 -# 3| v3_1(Void) = EnterFunction : -# 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 5| r5_1(glval) = VariableAddress[x] : -# 5| r5_2(Int32) = Constant[10] : -# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 6| r6_1(glval) = VariableAddress[a] : -# 6| r6_2(glval) = VariableAddress[x] : -# 6| r6_3(Int32) = Load : &:r6_2, ~mu3_3 -# 6| r6_4(Int32) = Constant[1] : -# 6| r6_5(Int32) = Add : r6_3, r6_4 -# 6| mu6_6(Int32) = Store : &:r6_2, r6_5 -# 6| mu6_7(Int32) = Store : &:r6_1, r6_3 -# 7| r7_1(glval) = VariableAddress[b] : -# 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load : &:r7_2, ~mu3_3 -# 7| r7_4(Int32) = Constant[1] : -# 7| r7_5(Int32) = Sub : r7_3, r7_4 -# 7| mu7_6(Int32) = Store : &:r7_2, r7_5 -# 7| mu7_7(Int32) = Store : &:r7_1, r7_5 -# 8| r8_1(glval) = VariableAddress[c] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| r8_3(Int32) = Load : &:r8_2, ~mu3_3 -# 8| r8_4(Int32) = Constant[1] : -# 8| r8_5(Int32) = Add : r8_3, r8_4 -# 8| mu8_6(Int32) = Store : &:r8_2, r8_5 -# 8| mu8_7(Int32) = Store : &:r8_1, r8_5 -# 9| r9_1(glval) = VariableAddress[x] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu3_3 -# 9| r9_3(Int32) = Constant[1] : -# 9| r9_4(Int32) = Sub : r9_2, r9_3 -# 9| mu9_5(Int32) = Store : &:r9_1, r9_4 -# 9| r9_6(glval) = VariableAddress[x] : -# 9| mu9_7(Int32) = Store : &:r9_6, r9_2 -# 3| v3_4(Void) = ReturnVoid : -# 3| v3_5(Void) = UnmodeledUse : mu* -# 3| v3_6(Void) = AliasedUse : ~mu3_3 -# 3| v3_7(Void) = ExitFunction : +# 3| v3_1(Void) = EnterFunction : +# 3| mu3_2() = AliasedDefinition : +# 5| r5_1(glval) = VariableAddress[x] : +# 5| r5_2(Int32) = Constant[10] : +# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 +# 6| r6_1(glval) = VariableAddress[a] : +# 6| r6_2(glval) = VariableAddress[x] : +# 6| r6_3(Int32) = Load : &:r6_2, ~m? +# 6| r6_4(Int32) = Constant[1] : +# 6| r6_5(Int32) = Add : r6_3, r6_4 +# 6| mu6_6(Int32) = Store : &:r6_2, r6_5 +# 6| mu6_7(Int32) = Store : &:r6_1, r6_3 +# 7| r7_1(glval) = VariableAddress[b] : +# 7| r7_2(glval) = VariableAddress[x] : +# 7| r7_3(Int32) = Load : &:r7_2, ~m? +# 7| r7_4(Int32) = Constant[1] : +# 7| r7_5(Int32) = Sub : r7_3, r7_4 +# 7| mu7_6(Int32) = Store : &:r7_2, r7_5 +# 7| mu7_7(Int32) = Store : &:r7_1, r7_5 +# 8| r8_1(glval) = VariableAddress[c] : +# 8| r8_2(glval) = VariableAddress[x] : +# 8| r8_3(Int32) = Load : &:r8_2, ~m? +# 8| r8_4(Int32) = Constant[1] : +# 8| r8_5(Int32) = Add : r8_3, r8_4 +# 8| mu8_6(Int32) = Store : &:r8_2, r8_5 +# 8| mu8_7(Int32) = Store : &:r8_1, r8_5 +# 9| r9_1(glval) = VariableAddress[x] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(Int32) = Constant[1] : +# 9| r9_4(Int32) = Sub : r9_2, r9_3 +# 9| mu9_5(Int32) = Store : &:r9_1, r9_4 +# 9| r9_6(glval) = VariableAddress[x] : +# 9| mu9_7(Int32) = Store : &:r9_6, r9_2 +# 3| v3_3(Void) = ReturnVoid : +# 3| v3_4(Void) = AliasedUse : ~m? +# 3| v3_5(Void) = ExitFunction : delegates.cs: # 6| System.Int32 Delegates.returns(System.Int32) # 6| Block 0 # 6| v6_1(Void) = EnterFunction : # 6| mu6_2() = AliasedDefinition : -# 6| mu6_3() = UnmodeledDefinition : -# 6| r6_4(glval) = VariableAddress[ret] : -# 6| mu6_5(Int32) = InitializeParameter[ret] : &:r6_4 +# 6| r6_3(glval) = VariableAddress[ret] : +# 6| mu6_4(Int32) = InitializeParameter[ret] : &:r6_3 # 8| r8_1(glval) = VariableAddress[#return] : # 8| r8_2(glval) = VariableAddress[ret] : -# 8| r8_3(Int32) = Load : &:r8_2, ~mu6_3 +# 8| r8_3(Int32) = Load : &:r8_2, ~m? # 8| mu8_4(Int32) = Store : &:r8_1, r8_3 -# 6| r6_6(glval) = VariableAddress[#return] : -# 6| v6_7(Void) = ReturnValue : &:r6_6, ~mu6_3 -# 6| v6_8(Void) = UnmodeledUse : mu* -# 6| v6_9(Void) = AliasedUse : ~mu6_3 -# 6| v6_10(Void) = ExitFunction : +# 6| r6_5(glval) = VariableAddress[#return] : +# 6| v6_6(Void) = ReturnValue : &:r6_5, ~m? +# 6| v6_7(Void) = AliasedUse : ~m? +# 6| v6_8(Void) = ExitFunction : # 11| System.Void Delegates.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 12| r12_1(glval) = VariableAddress[del1] : # 12| r12_2(Del) = NewObj : # 12| r12_3() = FunctionAddress[Del] : # 12| r12_4(glval) = FunctionAddress[returns] : # 12| v12_5(Void) = Call : func:r12_3, this:r12_2, 0:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~mu11_3 +# 12| mu12_6() = ^CallSideEffect : ~m? # 12| mu12_7(Del) = Store : &:r12_1, r12_2 # 13| r13_1(glval) = VariableAddress[del1] : -# 13| r13_2(Del) = Load : &:r13_1, ~mu11_3 +# 13| r13_2(Del) = Load : &:r13_1, ~m? # 13| r13_3() = FunctionAddress[Invoke] : # 13| r13_4(Int32) = Constant[5] : # 13| v13_5(Void) = Call : func:r13_3, this:r13_2, 0:r13_4 -# 13| mu13_6() = ^CallSideEffect : ~mu11_3 -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 13| mu13_6() = ^CallSideEffect : ~m? +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : events.cs: # 8| System.Void Events..ctor() # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : +# 8| r8_3(glval) = InitializeThis : # 10| r10_1(MyDel) = NewObj : # 10| r10_2() = FunctionAddress[MyDel] : # 10| r10_3(glval) = FunctionAddress[Fun] : # 10| v10_4(Void) = Call : func:r10_2, this:r10_1, 0:r10_3 -# 10| mu10_5() = ^CallSideEffect : ~mu8_3 -# 10| r10_6(Events) = CopyValue : r8_4 +# 10| mu10_5() = ^CallSideEffect : ~m? +# 10| r10_6(Events) = CopyValue : r8_3 # 10| r10_7(glval) = FieldAddress[Inst] : r10_6 # 10| mu10_8(MyDel) = Store : &:r10_7, r10_1 -# 8| v8_5(Void) = ReturnVoid : -# 8| v8_6(Void) = UnmodeledUse : mu* -# 8| v8_7(Void) = AliasedUse : ~mu8_3 -# 8| v8_8(Void) = ExitFunction : +# 8| v8_4(Void) = ReturnVoid : +# 8| v8_5(Void) = AliasedUse : ~m? +# 8| v8_6(Void) = ExitFunction : # 13| System.Void Events.AddEvent() # 13| Block 0 # 13| v13_1(Void) = EnterFunction : # 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = InitializeThis : -# 15| r15_1(Events) = CopyValue : r13_4 +# 13| r13_3(glval) = InitializeThis : +# 15| r15_1(Events) = CopyValue : r13_3 # 15| r15_2() = FunctionAddress[add_MyEvent] : -# 15| r15_3(Events) = CopyValue : r13_4 +# 15| r15_3(Events) = CopyValue : r13_3 # 15| r15_4(glval) = FieldAddress[Inst] : r15_3 -# 15| r15_5(MyDel) = Load : &:r15_4, ~mu13_3 +# 15| r15_5(MyDel) = Load : &:r15_4, ~m? # 15| v15_6(Void) = Call : func:r15_2, this:r15_1, 0:r15_5 -# 15| mu15_7() = ^CallSideEffect : ~mu13_3 -# 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = UnmodeledUse : mu* -# 13| v13_7(Void) = AliasedUse : ~mu13_3 -# 13| v13_8(Void) = ExitFunction : +# 15| mu15_7() = ^CallSideEffect : ~m? +# 13| v13_4(Void) = ReturnVoid : +# 13| v13_5(Void) = AliasedUse : ~m? +# 13| v13_6(Void) = ExitFunction : # 18| System.Void Events.RemoveEvent() # 18| Block 0 # 18| v18_1(Void) = EnterFunction : # 18| mu18_2() = AliasedDefinition : -# 18| mu18_3() = UnmodeledDefinition : -# 18| r18_4(glval) = InitializeThis : -# 20| r20_1(Events) = CopyValue : r18_4 +# 18| r18_3(glval) = InitializeThis : +# 20| r20_1(Events) = CopyValue : r18_3 # 20| r20_2() = FunctionAddress[remove_MyEvent] : -# 20| r20_3(Events) = CopyValue : r18_4 +# 20| r20_3(Events) = CopyValue : r18_3 # 20| r20_4(glval) = FieldAddress[Inst] : r20_3 -# 20| r20_5(MyDel) = Load : &:r20_4, ~mu18_3 +# 20| r20_5(MyDel) = Load : &:r20_4, ~m? # 20| v20_6(Void) = Call : func:r20_2, this:r20_1, 0:r20_5 -# 20| mu20_7() = ^CallSideEffect : ~mu18_3 -# 18| v18_5(Void) = ReturnVoid : -# 18| v18_6(Void) = UnmodeledUse : mu* -# 18| v18_7(Void) = AliasedUse : ~mu18_3 -# 18| v18_8(Void) = ExitFunction : +# 20| mu20_7() = ^CallSideEffect : ~m? +# 18| v18_4(Void) = ReturnVoid : +# 18| v18_5(Void) = AliasedUse : ~m? +# 18| v18_6(Void) = ExitFunction : # 23| System.String Events.Fun(System.String) # 23| Block 0 # 23| v23_1(Void) = EnterFunction : # 23| mu23_2() = AliasedDefinition : -# 23| mu23_3() = UnmodeledDefinition : -# 23| r23_4(glval) = InitializeThis : -# 23| r23_5(glval) = VariableAddress[str] : -# 23| mu23_6(String) = InitializeParameter[str] : &:r23_5 +# 23| r23_3(glval) = InitializeThis : +# 23| r23_4(glval) = VariableAddress[str] : +# 23| mu23_5(String) = InitializeParameter[str] : &:r23_4 # 25| r25_1(glval) = VariableAddress[#return] : # 25| r25_2(glval) = VariableAddress[str] : -# 25| r25_3(String) = Load : &:r25_2, ~mu23_3 +# 25| r25_3(String) = Load : &:r25_2, ~m? # 25| mu25_4(String) = Store : &:r25_1, r25_3 -# 23| r23_7(glval) = VariableAddress[#return] : -# 23| v23_8(Void) = ReturnValue : &:r23_7, ~mu23_3 -# 23| v23_9(Void) = UnmodeledUse : mu* -# 23| v23_10(Void) = AliasedUse : ~mu23_3 -# 23| v23_11(Void) = ExitFunction : +# 23| r23_6(glval) = VariableAddress[#return] : +# 23| v23_7(Void) = ReturnValue : &:r23_6, ~m? +# 23| v23_8(Void) = AliasedUse : ~m? +# 23| v23_9(Void) = ExitFunction : # 28| System.Void Events.Main(System.String[]) # 28| Block 0 # 28| v28_1(Void) = EnterFunction : # 28| mu28_2() = AliasedDefinition : -# 28| mu28_3() = UnmodeledDefinition : -# 28| r28_4(glval) = VariableAddress[args] : -# 28| mu28_5(String[]) = InitializeParameter[args] : &:r28_4 +# 28| r28_3(glval) = VariableAddress[args] : +# 28| mu28_4(String[]) = InitializeParameter[args] : &:r28_3 # 30| r30_1(glval) = VariableAddress[obj] : # 30| r30_2(Events) = NewObj : # 30| r30_3() = FunctionAddress[Events] : # 30| v30_4(Void) = Call : func:r30_3, this:r30_2 -# 30| mu30_5() = ^CallSideEffect : ~mu28_3 +# 30| mu30_5() = ^CallSideEffect : ~m? # 30| mu30_6(Events) = Store : &:r30_1, r30_2 # 31| r31_1(glval) = VariableAddress[obj] : -# 31| r31_2(Events) = Load : &:r31_1, ~mu28_3 +# 31| r31_2(Events) = Load : &:r31_1, ~m? # 31| r31_3() = FunctionAddress[AddEvent] : # 31| v31_4(Void) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu28_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 32| r32_1(glval) = VariableAddress[result] : # 32| r32_2(glval) = VariableAddress[obj] : -# 32| r32_3(Events) = Load : &:r32_2, ~mu28_3 +# 32| r32_3(Events) = Load : &:r32_2, ~m? # 32| r32_4() = FunctionAddress[Invoke] : # 32| r32_5(String) = StringConstant["string"] : # 32| v32_6(Void) = Call : func:r32_4, this:r32_3, 0:r32_5 -# 32| mu32_7() = ^CallSideEffect : ~mu28_3 +# 32| mu32_7() = ^CallSideEffect : ~m? # 32| mu32_8(String) = Store : &:r32_1, v32_6 # 33| r33_1(glval) = VariableAddress[obj] : -# 33| r33_2(Events) = Load : &:r33_1, ~mu28_3 +# 33| r33_2(Events) = Load : &:r33_1, ~m? # 33| r33_3() = FunctionAddress[RemoveEvent] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu28_3 -# 28| v28_6(Void) = ReturnVoid : -# 28| v28_7(Void) = UnmodeledUse : mu* -# 28| v28_8(Void) = AliasedUse : ~mu28_3 -# 28| v28_9(Void) = ExitFunction : +# 33| mu33_5() = ^CallSideEffect : ~m? +# 28| v28_5(Void) = ReturnVoid : +# 28| v28_6(Void) = AliasedUse : ~m? +# 28| v28_7(Void) = ExitFunction : foreach.cs: # 4| System.Void ForEach.Main() # 4| Block 0 # 4| v4_1(Void) = EnterFunction : # 4| mu4_2() = AliasedDefinition : -# 4| mu4_3() = UnmodeledDefinition : # 5| r5_1(glval) = VariableAddress[a_array] : # 5| mu5_2(Int32[]) = Uninitialized[a_array] : &:r5_1 # 5| r5_3(Int32) = Constant[0] : @@ -642,19 +603,19 @@ foreach.cs: # 5| mu5_30(Int32) = Store : &:r5_28, r5_29 # 7| r7_1(glval) = VariableAddress[#temp7:9] : # 7| r7_2(glval) = VariableAddress[a_array] : -# 7| r7_3(Int32[]) = Load : &:r7_2, ~mu4_3 +# 7| r7_3(Int32[]) = Load : &:r7_2, ~m? # 7| r7_4() = FunctionAddress[GetEnumerator] : # 7| r7_5(IEnumerator) = Call : func:r7_4, this:r7_3 -# 7| mu7_6() = ^CallSideEffect : ~mu4_3 +# 7| mu7_6() = ^CallSideEffect : ~m? # 7| mu7_7(IEnumerator) = Store : &:r7_1, r7_5 #-----| Goto -> Block 1 # 7| Block 1 # 7| r7_8(glval) = VariableAddress[#temp7:9] : -# 7| r7_9(Boolean) = Load : &:r7_8, ~mu4_3 +# 7| r7_9(Boolean) = Load : &:r7_8, ~m? # 7| r7_10() = FunctionAddress[MoveNext] : # 7| r7_11(Boolean) = Call : func:r7_10, this:r7_9 -# 7| mu7_12() = ^CallSideEffect : ~mu4_3 +# 7| mu7_12() = ^CallSideEffect : ~m? # 7| v7_13(Void) = ConditionalBranch : r7_11 #-----| False -> Block 3 #-----| True -> Block 2 @@ -662,320 +623,298 @@ foreach.cs: # 7| Block 2 # 7| r7_14(glval) = VariableAddress[items] : # 7| r7_15(glval) = VariableAddress[#temp7:9] : -# 7| r7_16(Boolean) = Load : &:r7_15, ~mu4_3 +# 7| r7_16(Boolean) = Load : &:r7_15, ~m? # 7| r7_17() = FunctionAddress[get_Current] : # 7| r7_18(Int32) = Call : func:r7_17, this:r7_16 -# 7| mu7_19() = ^CallSideEffect : ~mu4_3 +# 7| mu7_19() = ^CallSideEffect : ~m? # 7| mu7_20(Int32) = Store : &:r7_14, r7_18 # 9| r9_1(glval) = VariableAddress[x] : # 9| r9_2(glval) = VariableAddress[items] : -# 9| r9_3(Int32) = Load : &:r9_2, ~mu4_3 +# 9| r9_3(Int32) = Load : &:r9_2, ~m? # 9| mu9_4(Int32) = Store : &:r9_1, r9_3 #-----| Goto (back edge) -> Block 1 # 7| Block 3 # 7| r7_21(glval) = VariableAddress[#temp7:9] : -# 7| r7_22(Boolean) = Load : &:r7_21, ~mu4_3 +# 7| r7_22(Boolean) = Load : &:r7_21, ~m? # 7| r7_23() = FunctionAddress[Dispose] : # 7| v7_24(Void) = Call : func:r7_23, this:r7_22 -# 7| mu7_25() = ^CallSideEffect : ~mu4_3 -# 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = UnmodeledUse : mu* -# 4| v4_6(Void) = AliasedUse : ~mu4_3 -# 4| v4_7(Void) = ExitFunction : +# 7| mu7_25() = ^CallSideEffect : ~m? +# 4| v4_3(Void) = ReturnVoid : +# 4| v4_4(Void) = AliasedUse : ~m? +# 4| v4_5(Void) = ExitFunction : func_with_param_call.cs: # 5| System.Int32 test_call_with_param.f(System.Int32,System.Int32) # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = VariableAddress[x] : -# 5| mu5_5(Int32) = InitializeParameter[x] : &:r5_4 -# 5| r5_6(glval) = VariableAddress[y] : -# 5| mu5_7(Int32) = InitializeParameter[y] : &:r5_6 +# 5| r5_3(glval) = VariableAddress[x] : +# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 +# 5| r5_5(glval) = VariableAddress[y] : +# 5| mu5_6(Int32) = InitializeParameter[y] : &:r5_5 # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load : &:r7_2, ~mu5_3 +# 7| r7_3(Int32) = Load : &:r7_2, ~m? # 7| r7_4(glval) = VariableAddress[y] : -# 7| r7_5(Int32) = Load : &:r7_4, ~mu5_3 +# 7| r7_5(Int32) = Load : &:r7_4, ~m? # 7| r7_6(Int32) = Add : r7_3, r7_5 # 7| mu7_7(Int32) = Store : &:r7_1, r7_6 -# 5| r5_8(glval) = VariableAddress[#return] : -# 5| v5_9(Void) = ReturnValue : &:r5_8, ~mu5_3 -# 5| v5_10(Void) = UnmodeledUse : mu* -# 5| v5_11(Void) = AliasedUse : ~mu5_3 -# 5| v5_12(Void) = ExitFunction : +# 5| r5_7(glval) = VariableAddress[#return] : +# 5| v5_8(Void) = ReturnValue : &:r5_7, ~m? +# 5| v5_9(Void) = AliasedUse : ~m? +# 5| v5_10(Void) = ExitFunction : # 10| System.Int32 test_call_with_param.g() # 10| Block 0 # 10| v10_1(Void) = EnterFunction : # 10| mu10_2() = AliasedDefinition : -# 10| mu10_3() = UnmodeledDefinition : # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2() = FunctionAddress[f] : # 12| r12_3(Int32) = Constant[2] : # 12| r12_4(Int32) = Constant[3] : # 12| r12_5(Int32) = Call : func:r12_2, 0:r12_3, 1:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~mu10_3 +# 12| mu12_6() = ^CallSideEffect : ~m? # 12| mu12_7(Int32) = Store : &:r12_1, r12_5 -# 10| r10_4(glval) = VariableAddress[#return] : -# 10| v10_5(Void) = ReturnValue : &:r10_4, ~mu10_3 -# 10| v10_6(Void) = UnmodeledUse : mu* -# 10| v10_7(Void) = AliasedUse : ~mu10_3 -# 10| v10_8(Void) = ExitFunction : +# 10| r10_3(glval) = VariableAddress[#return] : +# 10| v10_4(Void) = ReturnValue : &:r10_3, ~m? +# 10| v10_5(Void) = AliasedUse : ~m? +# 10| v10_6(Void) = ExitFunction : indexers.cs: # 8| System.String Indexers.MyClass.get_Item(System.Int32) # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : +# 8| r8_3(glval) = InitializeThis : # 6| r6_1(glval) = VariableAddress[index] : # 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 # 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(MyClass) = CopyValue : r8_4 +# 10| r10_2(MyClass) = CopyValue : r8_3 # 10| r10_3(glval) = FieldAddress[address] : r10_2 # 10| r10_4(String[]) = ElementsAddress : r10_3 # 10| r10_5(glval) = VariableAddress[index] : -# 10| r10_6(Int32) = Load : &:r10_5, ~mu8_3 +# 10| r10_6(Int32) = Load : &:r10_5, ~m? # 10| r10_7(String[]) = PointerAdd[8] : r10_4, r10_6 -# 10| r10_8(String) = Load : &:r10_7, ~mu8_3 +# 10| r10_8(String) = Load : &:r10_7, ~m? # 10| mu10_9(String) = Store : &:r10_1, r10_8 -# 8| r8_5(glval) = VariableAddress[#return] : -# 8| v8_6(Void) = ReturnValue : &:r8_5, ~mu8_3 -# 8| v8_7(Void) = UnmodeledUse : mu* -# 8| v8_8(Void) = AliasedUse : ~mu8_3 -# 8| v8_9(Void) = ExitFunction : +# 8| r8_4(glval) = VariableAddress[#return] : +# 8| v8_5(Void) = ReturnValue : &:r8_4, ~m? +# 8| v8_6(Void) = AliasedUse : ~m? +# 8| v8_7(Void) = ExitFunction : # 12| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : -# 12| r12_4(glval) = InitializeThis : +# 12| r12_3(glval) = InitializeThis : # 6| r6_1(glval) = VariableAddress[index] : # 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 -# 12| r12_5(glval) = VariableAddress[value] : -# 12| mu12_6(String) = InitializeParameter[value] : &:r12_5 +# 12| r12_4(glval) = VariableAddress[value] : +# 12| mu12_5(String) = InitializeParameter[value] : &:r12_4 # 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(String) = Load : &:r14_1, ~mu12_3 -# 14| r14_3(MyClass) = CopyValue : r12_4 +# 14| r14_2(String) = Load : &:r14_1, ~m? +# 14| r14_3(MyClass) = CopyValue : r12_3 # 14| r14_4(glval) = FieldAddress[address] : r14_3 # 14| r14_5(String[]) = ElementsAddress : r14_4 # 14| r14_6(glval) = VariableAddress[index] : -# 14| r14_7(Int32) = Load : &:r14_6, ~mu12_3 +# 14| r14_7(Int32) = Load : &:r14_6, ~m? # 14| r14_8(String[]) = PointerAdd[8] : r14_5, r14_7 # 14| mu14_9(String) = Store : &:r14_8, r14_2 -# 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = UnmodeledUse : mu* -# 12| v12_9(Void) = AliasedUse : ~mu12_3 -# 12| v12_10(Void) = ExitFunction : +# 12| v12_6(Void) = ReturnVoid : +# 12| v12_7(Void) = AliasedUse : ~m? +# 12| v12_8(Void) = ExitFunction : # 19| System.Void Indexers.Main() # 19| Block 0 # 19| v19_1(Void) = EnterFunction : # 19| mu19_2() = AliasedDefinition : -# 19| mu19_3() = UnmodeledDefinition : # 21| r21_1(glval) = VariableAddress[inst] : # 21| r21_2(MyClass) = NewObj : # 21| r21_3() = FunctionAddress[MyClass] : # 21| v21_4(Void) = Call : func:r21_3, this:r21_2 -# 21| mu21_5() = ^CallSideEffect : ~mu19_3 +# 21| mu21_5() = ^CallSideEffect : ~m? # 21| mu21_6(MyClass) = Store : &:r21_1, r21_2 # 22| r22_1(glval) = VariableAddress[inst] : -# 22| r22_2(MyClass) = Load : &:r22_1, ~mu19_3 +# 22| r22_2(MyClass) = Load : &:r22_1, ~m? # 22| r22_3() = FunctionAddress[set_Item] : # 22| r22_4(Int32) = Constant[0] : # 22| r22_5(String) = StringConstant["str1"] : # 22| v22_6(Void) = Call : func:r22_3, this:r22_2, 0:r22_4, 1:r22_5 -# 22| mu22_7() = ^CallSideEffect : ~mu19_3 +# 22| mu22_7() = ^CallSideEffect : ~m? # 23| r23_1(glval) = VariableAddress[inst] : -# 23| r23_2(MyClass) = Load : &:r23_1, ~mu19_3 +# 23| r23_2(MyClass) = Load : &:r23_1, ~m? # 23| r23_3() = FunctionAddress[set_Item] : # 23| r23_4(Int32) = Constant[1] : # 23| r23_5(String) = StringConstant["str1"] : # 23| v23_6(Void) = Call : func:r23_3, this:r23_2, 0:r23_4, 1:r23_5 -# 23| mu23_7() = ^CallSideEffect : ~mu19_3 +# 23| mu23_7() = ^CallSideEffect : ~m? # 24| r24_1(glval) = VariableAddress[inst] : -# 24| r24_2(MyClass) = Load : &:r24_1, ~mu19_3 +# 24| r24_2(MyClass) = Load : &:r24_1, ~m? # 24| r24_3() = FunctionAddress[set_Item] : # 24| r24_4(Int32) = Constant[1] : # 24| r24_5(glval) = VariableAddress[inst] : -# 24| r24_6(MyClass) = Load : &:r24_5, ~mu19_3 +# 24| r24_6(MyClass) = Load : &:r24_5, ~m? # 24| r24_7() = FunctionAddress[get_Item] : # 24| r24_8(Int32) = Constant[0] : # 24| r24_9(String) = Call : func:r24_7, this:r24_6, 0:r24_8 -# 24| mu24_10() = ^CallSideEffect : ~mu19_3 +# 24| mu24_10() = ^CallSideEffect : ~m? # 24| v24_11(Void) = Call : func:r24_3, this:r24_2, 0:r24_4, 1:r24_9 -# 24| mu24_12() = ^CallSideEffect : ~mu19_3 -# 19| v19_4(Void) = ReturnVoid : -# 19| v19_5(Void) = UnmodeledUse : mu* -# 19| v19_6(Void) = AliasedUse : ~mu19_3 -# 19| v19_7(Void) = ExitFunction : +# 24| mu24_12() = ^CallSideEffect : ~m? +# 19| v19_3(Void) = ReturnVoid : +# 19| v19_4(Void) = AliasedUse : ~m? +# 19| v19_5(Void) = ExitFunction : inheritance_polymorphism.cs: # 3| System.Int32 A.function() # 3| Block 0 # 3| v3_1(Void) = EnterFunction : # 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 3| r3_4(glval) = InitializeThis : +# 3| r3_3(glval) = InitializeThis : # 5| r5_1(glval) = VariableAddress[#return] : # 5| r5_2(Int32) = Constant[0] : # 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 3| r3_5(glval) = VariableAddress[#return] : -# 3| v3_6(Void) = ReturnValue : &:r3_5, ~mu3_3 -# 3| v3_7(Void) = UnmodeledUse : mu* -# 3| v3_8(Void) = AliasedUse : ~mu3_3 -# 3| v3_9(Void) = ExitFunction : +# 3| r3_4(glval) = VariableAddress[#return] : +# 3| v3_5(Void) = ReturnValue : &:r3_4, ~m? +# 3| v3_6(Void) = AliasedUse : ~m? +# 3| v3_7(Void) = ExitFunction : # 15| System.Int32 C.function() # 15| Block 0 # 15| v15_1(Void) = EnterFunction : # 15| mu15_2() = AliasedDefinition : -# 15| mu15_3() = UnmodeledDefinition : -# 15| r15_4(glval) = InitializeThis : +# 15| r15_3(glval) = InitializeThis : # 17| r17_1(glval) = VariableAddress[#return] : # 17| r17_2(Int32) = Constant[1] : # 17| mu17_3(Int32) = Store : &:r17_1, r17_2 -# 15| r15_5(glval) = VariableAddress[#return] : -# 15| v15_6(Void) = ReturnValue : &:r15_5, ~mu15_3 -# 15| v15_7(Void) = UnmodeledUse : mu* -# 15| v15_8(Void) = AliasedUse : ~mu15_3 -# 15| v15_9(Void) = ExitFunction : +# 15| r15_4(glval) = VariableAddress[#return] : +# 15| v15_5(Void) = ReturnValue : &:r15_4, ~m? +# 15| v15_6(Void) = AliasedUse : ~m? +# 15| v15_7(Void) = ExitFunction : # 23| System.Void Program.Main() # 23| Block 0 # 23| v23_1(Void) = EnterFunction : # 23| mu23_2() = AliasedDefinition : -# 23| mu23_3() = UnmodeledDefinition : # 25| r25_1(glval) = VariableAddress[objB] : # 25| r25_2(B) = NewObj : # 25| r25_3() = FunctionAddress[B] : # 25| v25_4(Void) = Call : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~mu23_3 +# 25| mu25_5() = ^CallSideEffect : ~m? # 25| mu25_6(B) = Store : &:r25_1, r25_2 # 26| r26_1(glval) = VariableAddress[objB] : -# 26| r26_2(B) = Load : &:r26_1, ~mu23_3 +# 26| r26_2(B) = Load : &:r26_1, ~m? # 26| r26_3() = FunctionAddress[function] : # 26| r26_4(Int32) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu23_3 +# 26| mu26_5() = ^CallSideEffect : ~m? # 29| r29_1(glval) = VariableAddress[objA] : # 29| mu29_2(A) = Uninitialized[objA] : &:r29_1 # 30| r30_1(glval) = VariableAddress[objB] : -# 30| r30_2(B) = Load : &:r30_1, ~mu23_3 +# 30| r30_2(B) = Load : &:r30_1, ~m? # 30| r30_3(A) = Convert : r30_2 # 30| r30_4(glval) = VariableAddress[objA] : # 30| mu30_5(A) = Store : &:r30_4, r30_3 # 31| r31_1(glval) = VariableAddress[objA] : -# 31| r31_2(A) = Load : &:r31_1, ~mu23_3 +# 31| r31_2(A) = Load : &:r31_1, ~m? # 31| r31_3() = FunctionAddress[function] : # 31| r31_4(Int32) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu23_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 33| r33_1(glval) = VariableAddress[objC] : # 33| r33_2(C) = NewObj : # 33| r33_3() = FunctionAddress[C] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu23_3 +# 33| mu33_5() = ^CallSideEffect : ~m? # 33| r33_6(A) = Convert : r33_2 # 33| mu33_7(A) = Store : &:r33_1, r33_2 # 34| r34_1(glval) = VariableAddress[objC] : -# 34| r34_2(A) = Load : &:r34_1, ~mu23_3 +# 34| r34_2(A) = Load : &:r34_1, ~m? # 34| r34_3() = FunctionAddress[function] : # 34| r34_4(Int32) = Call : func:r34_3, this:r34_2 -# 34| mu34_5() = ^CallSideEffect : ~mu23_3 -# 23| v23_4(Void) = ReturnVoid : -# 23| v23_5(Void) = UnmodeledUse : mu* -# 23| v23_6(Void) = AliasedUse : ~mu23_3 -# 23| v23_7(Void) = ExitFunction : +# 34| mu34_5() = ^CallSideEffect : ~m? +# 23| v23_3(Void) = ReturnVoid : +# 23| v23_4(Void) = AliasedUse : ~m? +# 23| v23_5(Void) = ExitFunction : inoutref.cs: # 11| System.Void InOutRef.set(MyClass,MyClass) # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : -# 11| r11_4(glval) = VariableAddress[o1] : -# 11| mu11_5(MyClass) = InitializeParameter[o1] : &:r11_4 -# 11| r11_6(glval) = VariableAddress[o2] : -# 11| mu11_7(MyClass) = InitializeParameter[o2] : &:r11_6 +# 11| r11_3(glval) = VariableAddress[o1] : +# 11| mu11_4(MyClass) = InitializeParameter[o1] : &:r11_3 +# 11| r11_5(glval) = VariableAddress[o2] : +# 11| mu11_6(MyClass) = InitializeParameter[o2] : &:r11_5 # 13| r13_1(glval) = VariableAddress[o2] : -# 13| r13_2(MyClass) = Load : &:r13_1, ~mu11_3 +# 13| r13_2(MyClass) = Load : &:r13_1, ~m? # 13| r13_3(glval) = VariableAddress[o1] : -# 13| r13_4(MyClass) = Load : &:r13_3, ~mu11_3 +# 13| r13_4(MyClass) = Load : &:r13_3, ~m? # 13| mu13_5(MyClass) = Store : &:r13_4, r13_2 -# 11| v11_8(Void) = ReturnVoid : -# 11| v11_9(Void) = UnmodeledUse : mu* -# 11| v11_10(Void) = AliasedUse : ~mu11_3 -# 11| v11_11(Void) = ExitFunction : +# 11| v11_7(Void) = ReturnVoid : +# 11| v11_8(Void) = AliasedUse : ~m? +# 11| v11_9(Void) = ExitFunction : # 16| System.Void InOutRef.F(System.Int32,MyStruct,MyStruct,MyClass,MyClass) # 16| Block 0 # 16| v16_1(Void) = EnterFunction : # 16| mu16_2() = AliasedDefinition : -# 16| mu16_3() = UnmodeledDefinition : -# 16| r16_4(glval) = VariableAddress[a] : -# 16| mu16_5(Int32) = InitializeParameter[a] : &:r16_4 -# 16| r16_6(glval) = VariableAddress[b] : -# 16| mu16_7(MyStruct) = InitializeParameter[b] : &:r16_6 -# 16| r16_8(glval) = VariableAddress[b1] : -# 16| mu16_9(MyStruct) = InitializeParameter[b1] : &:r16_8 -# 16| r16_10(glval) = VariableAddress[c] : -# 16| mu16_11(MyClass) = InitializeParameter[c] : &:r16_10 -# 16| r16_12(glval) = VariableAddress[c1] : -# 16| mu16_13(MyClass) = InitializeParameter[c1] : &:r16_12 +# 16| r16_3(glval) = VariableAddress[a] : +# 16| mu16_4(Int32) = InitializeParameter[a] : &:r16_3 +# 16| r16_5(glval) = VariableAddress[b] : +# 16| mu16_6(MyStruct) = InitializeParameter[b] : &:r16_5 +# 16| r16_7(glval) = VariableAddress[b1] : +# 16| mu16_8(MyStruct) = InitializeParameter[b1] : &:r16_7 +# 16| r16_9(glval) = VariableAddress[c] : +# 16| mu16_10(MyClass) = InitializeParameter[c] : &:r16_9 +# 16| r16_11(glval) = VariableAddress[c1] : +# 16| mu16_12(MyClass) = InitializeParameter[c1] : &:r16_11 # 18| r18_1(Int32) = Constant[0] : # 18| r18_2(glval) = VariableAddress[b] : -# 18| r18_3(MyStruct) = Load : &:r18_2, ~mu16_3 +# 18| r18_3(MyStruct) = Load : &:r18_2, ~m? # 18| r18_4(glval) = FieldAddress[fld] : r18_3 # 18| mu18_5(Int32) = Store : &:r18_4, r18_1 # 19| r19_1(glval) = VariableAddress[b] : -# 19| r19_2(MyStruct) = Load : &:r19_1, ~mu16_3 +# 19| r19_2(MyStruct) = Load : &:r19_1, ~m? # 19| r19_3(glval) = FieldAddress[fld] : r19_2 -# 19| r19_4(Int32) = Load : &:r19_3, ~mu16_3 +# 19| r19_4(Int32) = Load : &:r19_3, ~m? # 19| r19_5(glval) = VariableAddress[a] : -# 19| r19_6(Int32) = Load : &:r19_5, ~mu16_3 +# 19| r19_6(Int32) = Load : &:r19_5, ~m? # 19| mu19_7(Int32) = Store : &:r19_6, r19_4 # 21| r21_1(Int32) = Constant[10] : # 21| r21_2(glval) = VariableAddress[c] : -# 21| r21_3(MyClass) = Load : &:r21_2, ~mu16_3 -# 21| r21_4(MyClass) = Load : &:r21_3, ~mu16_3 +# 21| r21_3(MyClass) = Load : &:r21_2, ~m? +# 21| r21_4(MyClass) = Load : &:r21_3, ~m? # 21| r21_5(glval) = FieldAddress[fld] : r21_4 # 21| mu21_6(Int32) = Store : &:r21_5, r21_1 # 22| r22_1(glval) = VariableAddress[c] : -# 22| r22_2(MyClass) = Load : &:r22_1, ~mu16_3 -# 22| r22_3(MyClass) = Load : &:r22_2, ~mu16_3 +# 22| r22_2(MyClass) = Load : &:r22_1, ~m? +# 22| r22_3(MyClass) = Load : &:r22_2, ~m? # 22| r22_4(glval) = FieldAddress[fld] : r22_3 -# 22| r22_5(Int32) = Load : &:r22_4, ~mu16_3 +# 22| r22_5(Int32) = Load : &:r22_4, ~m? # 22| r22_6(glval) = VariableAddress[a] : -# 22| r22_7(Int32) = Load : &:r22_6, ~mu16_3 +# 22| r22_7(Int32) = Load : &:r22_6, ~m? # 22| mu22_8(Int32) = Store : &:r22_7, r22_5 # 24| r24_1(glval) = VariableAddress[b1] : -# 24| r24_2(MyStruct) = Load : &:r24_1, ~mu16_3 -# 24| r24_3(MyStruct) = Load : &:r24_2, ~mu16_3 +# 24| r24_2(MyStruct) = Load : &:r24_1, ~m? +# 24| r24_3(MyStruct) = Load : &:r24_2, ~m? # 24| r24_4(glval) = VariableAddress[b] : -# 24| r24_5(MyStruct) = Load : &:r24_4, ~mu16_3 +# 24| r24_5(MyStruct) = Load : &:r24_4, ~m? # 24| mu24_6(MyStruct) = Store : &:r24_5, r24_3 # 26| r26_1() = FunctionAddress[set] : # 26| r26_2(glval) = VariableAddress[c] : -# 26| r26_3(MyClass) = Load : &:r26_2, ~mu16_3 +# 26| r26_3(MyClass) = Load : &:r26_2, ~m? # 26| r26_4(glval) = VariableAddress[c1] : -# 26| r26_5(MyClass) = Load : &:r26_4, ~mu16_3 -# 26| r26_6(MyClass) = Load : &:r26_5, ~mu16_3 +# 26| r26_5(MyClass) = Load : &:r26_4, ~m? +# 26| r26_6(MyClass) = Load : &:r26_5, ~m? # 26| v26_7(Void) = Call : func:r26_1, 0:r26_3, 1:r26_6 -# 26| mu26_8() = ^CallSideEffect : ~mu16_3 -# 16| v16_14(Void) = ReturnVoid : -# 16| v16_15(Void) = UnmodeledUse : mu* -# 16| v16_16(Void) = AliasedUse : ~mu16_3 -# 16| v16_17(Void) = ExitFunction : +# 26| mu26_8() = ^CallSideEffect : ~m? +# 16| v16_13(Void) = ReturnVoid : +# 16| v16_14(Void) = AliasedUse : ~m? +# 16| v16_15(Void) = ExitFunction : # 29| System.Void InOutRef.Main() # 29| Block 0 # 29| v29_1(Void) = EnterFunction : # 29| mu29_2() = AliasedDefinition : -# 29| mu29_3() = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[a] : # 31| r31_2(Int32) = Constant[0] : # 31| mu31_3(Int32) = Store : &:r31_1, r31_2 @@ -983,14 +922,14 @@ inoutref.cs: # 32| r32_2(MyStruct) = NewObj : # 32| r32_3() = FunctionAddress[MyStruct] : # 32| v32_4(Void) = Call : func:r32_3, this:r32_2 -# 32| mu32_5() = ^CallSideEffect : ~mu29_3 -# 32| r32_6(MyStruct) = Load : &:r32_2, ~mu29_3 +# 32| mu32_5() = ^CallSideEffect : ~m? +# 32| r32_6(MyStruct) = Load : &:r32_2, ~m? # 32| mu32_7(MyStruct) = Store : &:r32_1, r32_6 # 33| r33_1(glval) = VariableAddress[c] : # 33| r33_2(MyClass) = NewObj : # 33| r33_3() = FunctionAddress[MyClass] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu29_3 +# 33| mu33_5() = ^CallSideEffect : ~m? # 33| mu33_6(MyClass) = Store : &:r33_1, r33_2 # 34| r34_1() = FunctionAddress[F] : # 34| r34_2(glval) = VariableAddress[a] : @@ -999,34 +938,32 @@ inoutref.cs: # 34| r34_5(glval) = VariableAddress[c] : # 34| r34_6(glval) = VariableAddress[c] : # 34| v34_7(Void) = Call : func:r34_1, 0:r34_2, 1:r34_3, 2:r34_4, 3:r34_5, 4:r34_6 -# 34| mu34_8() = ^CallSideEffect : ~mu29_3 +# 34| mu34_8() = ^CallSideEffect : ~m? # 36| r36_1(glval) = VariableAddress[x] : # 36| r36_2(glval) = VariableAddress[b] : # 36| r36_3(glval) = FieldAddress[fld] : r36_2 -# 36| r36_4(Int32) = Load : &:r36_3, ~mu29_3 +# 36| r36_4(Int32) = Load : &:r36_3, ~m? # 36| mu36_5(Int32) = Store : &:r36_1, r36_4 -# 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = UnmodeledUse : mu* -# 29| v29_6(Void) = AliasedUse : ~mu29_3 -# 29| v29_7(Void) = ExitFunction : +# 29| v29_3(Void) = ReturnVoid : +# 29| v29_4(Void) = AliasedUse : ~m? +# 29| v29_5(Void) = ExitFunction : isexpr.cs: # 8| System.Void IsExpr.Main() # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : # 10| r10_1(glval) = VariableAddress[obj] : # 10| r10_2(null) = Constant[null] : # 10| r10_3(Is_A) = Convert : r10_2 # 10| mu10_4(Is_A) = Store : &:r10_1, r10_2 # 12| r12_1(glval) = VariableAddress[o] : # 12| r12_2(glval) = VariableAddress[obj] : -# 12| r12_3(Is_A) = Load : &:r12_2, ~mu8_3 +# 12| r12_3(Is_A) = Load : &:r12_2, ~m? # 12| r12_4(Object) = Convert : r12_3 # 12| mu12_5(Object) = Store : &:r12_1, r12_3 # 13| r13_1(glval) = VariableAddress[o] : -# 13| r13_2(Object) = Load : &:r13_1, ~mu8_3 +# 13| r13_2(Object) = Load : &:r13_1, ~m? # 13| r13_3(Is_A) = CheckedConvertOrNull : r13_2 # 13| r13_4(Is_A) = Constant[0] : # 13| r13_5(glval) = VariableAddress[tmp] : @@ -1037,10 +974,9 @@ isexpr.cs: #-----| True -> Block 3 # 8| Block 1 -# 8| v8_4(Void) = ReturnVoid : -# 8| v8_5(Void) = UnmodeledUse : mu* -# 8| v8_6(Void) = AliasedUse : ~mu8_3 -# 8| v8_7(Void) = ExitFunction : +# 8| v8_3(Void) = ReturnVoid : +# 8| v8_4(Void) = AliasedUse : ~m? +# 8| v8_5(Void) = ExitFunction : # 13| Block 2 # 13| v13_9(Void) = ConditionalBranch : r13_7 @@ -1054,15 +990,15 @@ isexpr.cs: # 15| Block 4 # 15| r15_1(glval) = VariableAddress[res] : # 15| r15_2(glval) = VariableAddress[tmp] : -# 15| r15_3(Is_A) = Load : &:r15_2, ~mu8_3 +# 15| r15_3(Is_A) = Load : &:r15_2, ~m? # 15| r15_4(glval) = FieldAddress[x] : r15_3 -# 15| r15_5(Int32) = Load : &:r15_4, ~mu8_3 +# 15| r15_5(Int32) = Load : &:r15_4, ~m? # 15| mu15_6(Int32) = Store : &:r15_1, r15_5 #-----| Goto -> Block 5 # 17| Block 5 # 17| r17_1(glval) = VariableAddress[o] : -# 17| r17_2(Object) = Load : &:r17_1, ~mu8_3 +# 17| r17_2(Object) = Load : &:r17_1, ~m? # 17| r17_3(Is_A) = CheckedConvertOrNull : r17_2 # 17| r17_4(Is_A) = Constant[0] : # 17| r17_5(Boolean) = CompareNE : r17_3, r17_4 @@ -1077,17 +1013,16 @@ isexpr.cs: jumps.cs: # 5| System.Void Jumps.Main() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 7| r7_1(glval) = VariableAddress[i] : -# 7| r7_2(Int32) = Constant[1] : -# 7| mu7_3(Int32) = Store : &:r7_1, r7_2 +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 7| r7_1(glval) = VariableAddress[i] : +# 7| r7_2(Int32) = Constant[1] : +# 7| mu7_3(Int32) = Store : &:r7_1, r7_2 #-----| Goto -> Block 1 # 7| Block 1 # 7| r7_4(glval) = VariableAddress[i] : -# 7| r7_5(Int32) = Load : &:r7_4, ~mu5_3 +# 7| r7_5(Int32) = Load : &:r7_4, ~m? # 7| r7_6(Int32) = Constant[10] : # 7| r7_7(Boolean) = CompareLE : r7_5, r7_6 # 7| v7_8(Void) = ConditionalBranch : r7_7 @@ -1096,7 +1031,7 @@ jumps.cs: # 9| Block 2 # 9| r9_1(glval) = VariableAddress[i] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu5_3 +# 9| r9_2(Int32) = Load : &:r9_1, ~m? # 9| r9_3(Int32) = Constant[3] : # 9| r9_4(Boolean) = CompareEQ : r9_2, r9_3 # 9| v9_5(Void) = ConditionalBranch : r9_4 @@ -1109,7 +1044,7 @@ jumps.cs: # 11| Block 4 # 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu5_3 +# 11| r11_2(Int32) = Load : &:r11_1, ~m? # 11| r11_3(Int32) = Constant[5] : # 11| r11_4(Boolean) = CompareEQ : r11_2, r11_3 # 11| v11_5(Void) = ConditionalBranch : r11_4 @@ -1124,7 +1059,7 @@ jumps.cs: # 13| r13_1() = FunctionAddress[WriteLine] : # 13| r13_2(String) = StringConstant["BreakAndContinue"] : # 13| v13_3(Void) = Call : func:r13_1, 0:r13_2 -# 13| mu13_4() = ^CallSideEffect : ~mu5_3 +# 13| mu13_4() = ^CallSideEffect : ~m? #-----| Goto -> Block 19 # 16| Block 7 @@ -1135,7 +1070,7 @@ jumps.cs: # 16| Block 8 # 16| r16_4(glval) = VariableAddress[i] : -# 16| r16_5(Int32) = Load : &:r16_4, ~mu5_3 +# 16| r16_5(Int32) = Load : &:r16_4, ~m? # 16| r16_6(Int32) = Constant[10] : # 16| r16_7(Boolean) = CompareLT : r16_5, r16_6 # 16| v16_8(Void) = ConditionalBranch : r16_7 @@ -1144,7 +1079,7 @@ jumps.cs: # 18| Block 9 # 18| r18_1(glval) = VariableAddress[i] : -# 18| r18_2(Int32) = Load : &:r18_1, ~mu5_3 +# 18| r18_2(Int32) = Load : &:r18_1, ~m? # 18| r18_3(Int32) = Constant[1] : # 18| r18_4(Int32) = Add : r18_2, r18_3 # 18| mu18_5(Int32) = Store : &:r18_1, r18_4 @@ -1165,12 +1100,12 @@ jumps.cs: # 25| Block 12 # 25| r25_1(glval) = VariableAddress[a] : -# 25| r25_2(Int32) = Load : &:r25_1, ~mu5_3 +# 25| r25_2(Int32) = Load : &:r25_1, ~m? # 25| r25_3(Int32) = Constant[1] : # 25| r25_4(Int32) = Add : r25_2, r25_3 # 25| mu25_5(Int32) = Store : &:r25_1, r25_4 # 26| r26_1(glval) = VariableAddress[a] : -# 26| r26_2(Int32) = Load : &:r26_1, ~mu5_3 +# 26| r26_2(Int32) = Load : &:r26_1, ~m? # 26| r26_3(Int32) = Constant[5] : # 26| r26_4(Boolean) = CompareEQ : r26_2, r26_3 # 26| v26_5(Void) = ConditionalBranch : r26_4 @@ -1183,7 +1118,7 @@ jumps.cs: # 28| Block 14 # 28| r28_1(glval) = VariableAddress[a] : -# 28| r28_2(Int32) = Load : &:r28_1, ~mu5_3 +# 28| r28_2(Int32) = Load : &:r28_1, ~m? # 28| r28_3(Int32) = Constant[10] : # 28| r28_4(Boolean) = CompareEQ : r28_2, r28_3 # 28| v28_5(Void) = ConditionalBranch : r28_4 @@ -1202,7 +1137,7 @@ jumps.cs: # 32| Block 17 # 32| r32_4(glval) = VariableAddress[i] : -# 32| r32_5(Int32) = Load : &:r32_4, ~mu5_3 +# 32| r32_5(Int32) = Load : &:r32_4, ~m? # 32| r32_6(Int32) = Constant[1] : # 32| r32_7(Int32) = Add : r32_5, r32_6 # 32| mu32_8(Int32) = Store : &:r32_4, r32_7 @@ -1210,7 +1145,7 @@ jumps.cs: # 32| Block 18 # 32| r32_9(glval) = VariableAddress[i] : -# 32| r32_10(Int32) = Load : &:r32_9, ~mu5_3 +# 32| r32_10(Int32) = Load : &:r32_9, ~m? # 32| r32_11(Int32) = Constant[10] : # 32| r32_12(Boolean) = CompareLE : r32_10, r32_11 # 32| v32_13(Void) = ConditionalBranch : r32_12 @@ -1219,7 +1154,7 @@ jumps.cs: # 7| Block 19 # 7| r7_9(glval) = VariableAddress[i] : -# 7| r7_10(Int32) = Load : &:r7_9, ~mu5_3 +# 7| r7_10(Int32) = Load : &:r7_9, ~m? # 7| r7_11(Int32) = Constant[1] : # 7| r7_12(Int32) = Add : r7_10, r7_11 # 7| mu7_13(Int32) = Store : &:r7_9, r7_12 @@ -1227,7 +1162,7 @@ jumps.cs: # 34| Block 20 # 34| r34_1(glval) = VariableAddress[i] : -# 34| r34_2(Int32) = Load : &:r34_1, ~mu5_3 +# 34| r34_2(Int32) = Load : &:r34_1, ~m? # 34| r34_3(Int32) = Constant[5] : # 34| r34_4(Boolean) = CompareEQ : r34_2, r34_3 # 34| v34_5(Void) = ConditionalBranch : r34_4 @@ -1243,172 +1178,160 @@ jumps.cs: # 38| r38_1() = FunctionAddress[WriteLine] : # 38| r38_2(String) = StringConstant["Done"] : # 38| v38_3(Void) = Call : func:r38_1, 0:r38_2 -# 38| mu38_4() = ^CallSideEffect : ~mu5_3 -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 38| mu38_4() = ^CallSideEffect : ~m? +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : lock.cs: # 5| System.Void LockTest.A() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[object] : # 7| r7_2(Object) = NewObj : # 7| r7_3() = FunctionAddress[Object] : # 7| v7_4(Void) = Call : func:r7_3, this:r7_2 -# 7| mu7_5() = ^CallSideEffect : ~mu5_3 +# 7| mu7_5() = ^CallSideEffect : ~m? # 7| mu7_6(Object) = Store : &:r7_1, r7_2 # 8| r8_1(glval) = VariableAddress[#temp8:9] : # 8| r8_2(glval) = VariableAddress[object] : -# 8| r8_3(Object) = Load : &:r8_2, ~mu5_3 +# 8| r8_3(Object) = Load : &:r8_2, ~m? # 8| mu8_4(Object) = Store : &:r8_1, r8_3 # 8| r8_5(glval) = VariableAddress[#temp8:9] : # 8| r8_6(Boolean) = Constant[false] : # 8| mu8_7(Boolean) = Store : &:r8_5, r8_6 # 8| r8_8() = FunctionAddress[Enter] : # 8| r8_9(glval) = VariableAddress[#temp8:9] : -# 8| r8_10(Object) = Load : &:r8_9, ~mu5_3 +# 8| r8_10(Object) = Load : &:r8_9, ~m? # 8| r8_11(glval) = VariableAddress[#temp8:9] : # 8| v8_12(Void) = Call : func:r8_8, 0:r8_10, 1:r8_11 -# 8| mu8_13() = ^CallSideEffect : ~mu5_3 +# 8| mu8_13() = ^CallSideEffect : ~m? # 10| r10_1() = FunctionAddress[WriteLine] : # 10| r10_2(glval) = VariableAddress[object] : -# 10| r10_3(Object) = Load : &:r10_2, ~mu5_3 +# 10| r10_3(Object) = Load : &:r10_2, ~m? # 10| r10_4() = FunctionAddress[ToString] : # 10| r10_5(String) = Call : func:r10_4, this:r10_3 -# 10| mu10_6() = ^CallSideEffect : ~mu5_3 +# 10| mu10_6() = ^CallSideEffect : ~m? # 10| v10_7(Void) = Call : func:r10_1, 0:r10_5 -# 10| mu10_8() = ^CallSideEffect : ~mu5_3 +# 10| mu10_8() = ^CallSideEffect : ~m? # 8| r8_14(glval) = VariableAddress[#temp8:9] : -# 8| r8_15(Boolean) = Load : &:r8_14, ~mu5_3 +# 8| r8_15(Boolean) = Load : &:r8_14, ~m? # 8| v8_16(Void) = ConditionalBranch : r8_15 #-----| False -> Block 1 #-----| True -> Block 2 # 5| Block 1 -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : # 8| Block 2 # 8| r8_17() = FunctionAddress[Exit] : # 8| r8_18(glval) = VariableAddress[#temp8:9] : -# 8| r8_19(Object) = Load : &:r8_18, ~mu5_3 +# 8| r8_19(Object) = Load : &:r8_18, ~m? # 8| v8_20(Void) = Call : func:r8_17, 0:r8_19 -# 8| mu8_21() = ^CallSideEffect : ~mu5_3 +# 8| mu8_21() = ^CallSideEffect : ~m? #-----| Goto -> Block 1 obj_creation.cs: # 7| System.Void ObjCreation.MyClass..ctor() # 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : -# 8| v8_1(Void) = NoOp : -# 7| v7_5(Void) = ReturnVoid : -# 7| v7_6(Void) = UnmodeledUse : mu* -# 7| v7_7(Void) = AliasedUse : ~mu7_3 -# 7| v7_8(Void) = ExitFunction : +# 7| v7_1(Void) = EnterFunction : +# 7| mu7_2() = AliasedDefinition : +# 7| r7_3(glval) = InitializeThis : +# 8| v8_1(Void) = NoOp : +# 7| v7_4(Void) = ReturnVoid : +# 7| v7_5(Void) = AliasedUse : ~m? +# 7| v7_6(Void) = ExitFunction : # 11| System.Void ObjCreation.MyClass..ctor(System.Int32) # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : -# 11| r11_4(glval) = InitializeThis : -# 11| r11_5(glval) = VariableAddress[_x] : -# 11| mu11_6(Int32) = InitializeParameter[_x] : &:r11_5 +# 11| r11_3(glval) = InitializeThis : +# 11| r11_4(glval) = VariableAddress[_x] : +# 11| mu11_5(Int32) = InitializeParameter[_x] : &:r11_4 # 13| r13_1(glval) = VariableAddress[_x] : -# 13| r13_2(Int32) = Load : &:r13_1, ~mu11_3 -# 13| r13_3(MyClass) = CopyValue : r11_4 +# 13| r13_2(Int32) = Load : &:r13_1, ~m? +# 13| r13_3(MyClass) = CopyValue : r11_3 # 13| r13_4(glval) = FieldAddress[x] : r13_3 # 13| mu13_5(Int32) = Store : &:r13_4, r13_2 -# 11| v11_7(Void) = ReturnVoid : -# 11| v11_8(Void) = UnmodeledUse : mu* -# 11| v11_9(Void) = AliasedUse : ~mu11_3 -# 11| v11_10(Void) = ExitFunction : +# 11| v11_6(Void) = ReturnVoid : +# 11| v11_7(Void) = AliasedUse : ~m? +# 11| v11_8(Void) = ExitFunction : # 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) # 17| Block 0 # 17| v17_1(Void) = EnterFunction : # 17| mu17_2() = AliasedDefinition : -# 17| mu17_3() = UnmodeledDefinition : -# 17| r17_4(glval) = VariableAddress[x] : -# 17| mu17_5(MyClass) = InitializeParameter[x] : &:r17_4 +# 17| r17_3(glval) = VariableAddress[x] : +# 17| mu17_4(MyClass) = InitializeParameter[x] : &:r17_3 # 18| v18_1(Void) = NoOp : -# 17| v17_6(Void) = ReturnVoid : -# 17| v17_7(Void) = UnmodeledUse : mu* -# 17| v17_8(Void) = AliasedUse : ~mu17_3 -# 17| v17_9(Void) = ExitFunction : +# 17| v17_5(Void) = ReturnVoid : +# 17| v17_6(Void) = AliasedUse : ~m? +# 17| v17_7(Void) = ExitFunction : # 21| System.Void ObjCreation.Main() # 21| Block 0 # 21| v21_1(Void) = EnterFunction : # 21| mu21_2() = AliasedDefinition : -# 21| mu21_3() = UnmodeledDefinition : # 23| r23_1(glval) = VariableAddress[obj] : # 23| r23_2(MyClass) = NewObj : # 23| r23_3() = FunctionAddress[MyClass] : # 23| r23_4(Int32) = Constant[100] : # 23| v23_5(Void) = Call : func:r23_3, this:r23_2, 0:r23_4 -# 23| mu23_6() = ^CallSideEffect : ~mu21_3 +# 23| mu23_6() = ^CallSideEffect : ~m? # 23| mu23_7(MyClass) = Store : &:r23_1, r23_2 # 24| r24_1(glval) = VariableAddress[obj_initlist] : # 24| r24_2(MyClass) = NewObj : # 24| r24_3() = FunctionAddress[MyClass] : # 24| v24_4(Void) = Call : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~mu21_3 +# 24| mu24_5() = ^CallSideEffect : ~m? # 24| r24_6(Int32) = Constant[101] : # 24| r24_7(glval) = FieldAddress[x] : r24_2 # 24| mu24_8(Int32) = Store : &:r24_7, r24_6 # 24| mu24_9(MyClass) = Store : &:r24_1, r24_2 # 25| r25_1(glval) = VariableAddress[a] : # 25| r25_2(glval) = VariableAddress[obj] : -# 25| r25_3(MyClass) = Load : &:r25_2, ~mu21_3 +# 25| r25_3(MyClass) = Load : &:r25_2, ~m? # 25| r25_4(glval) = FieldAddress[x] : r25_3 -# 25| r25_5(Int32) = Load : &:r25_4, ~mu21_3 +# 25| r25_5(Int32) = Load : &:r25_4, ~m? # 25| mu25_6(Int32) = Store : &:r25_1, r25_5 # 27| r27_1() = FunctionAddress[SomeFun] : # 27| r27_2(MyClass) = NewObj : # 27| r27_3() = FunctionAddress[MyClass] : # 27| r27_4(Int32) = Constant[100] : # 27| v27_5(Void) = Call : func:r27_3, this:r27_2, 0:r27_4 -# 27| mu27_6() = ^CallSideEffect : ~mu21_3 +# 27| mu27_6() = ^CallSideEffect : ~m? # 27| v27_7(Void) = Call : func:r27_1, 0:r27_2 -# 27| mu27_8() = ^CallSideEffect : ~mu21_3 -# 21| v21_4(Void) = ReturnVoid : -# 21| v21_5(Void) = UnmodeledUse : mu* -# 21| v21_6(Void) = AliasedUse : ~mu21_3 -# 21| v21_7(Void) = ExitFunction : +# 27| mu27_8() = ^CallSideEffect : ~m? +# 21| v21_3(Void) = ReturnVoid : +# 21| v21_4(Void) = AliasedUse : ~m? +# 21| v21_5(Void) = ExitFunction : pointers.cs: # 3| System.Void Pointers.addone(System.Int32[]) # 3| Block 0 # 3| v3_1(Void) = EnterFunction : # 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 3| r3_4(glval) = VariableAddress[arr] : -# 3| mu3_5(Int32[]) = InitializeParameter[arr] : &:r3_4 +# 3| r3_3(glval) = VariableAddress[arr] : +# 3| mu3_4(Int32[]) = InitializeParameter[arr] : &:r3_3 # 5| r5_1(glval) = VariableAddress[length] : # 5| r5_2(glval) = VariableAddress[arr] : -# 5| r5_3(Int32[]) = Load : &:r5_2, ~mu3_3 +# 5| r5_3(Int32[]) = Load : &:r5_2, ~m? # 5| r5_4() = FunctionAddress[get_Length] : # 5| r5_5(Int32) = Call : func:r5_4, this:r5_3 -# 5| mu5_6() = ^CallSideEffect : ~mu3_3 +# 5| mu5_6() = ^CallSideEffect : ~m? # 5| mu5_7(Int32) = Store : &:r5_1, r5_5 # 6| r6_1(glval) = VariableAddress[b] : # 6| r6_2(glval) = VariableAddress[arr] : -# 6| r6_3(Int32[]) = Load : &:r6_2, ~mu3_3 +# 6| r6_3(Int32[]) = Load : &:r6_2, ~m? # 6| r6_4(Int32*) = Convert : r6_3 # 6| mu6_5(Int32*) = Store : &:r6_1, r6_3 # 8| r8_1(glval) = VariableAddress[p] : # 8| r8_2(glval) = VariableAddress[b] : -# 8| r8_3(Int32*) = Load : &:r8_2, ~mu3_3 +# 8| r8_3(Int32*) = Load : &:r8_2, ~m? # 8| mu8_4(Int32*) = Store : &:r8_1, r8_3 # 9| r9_1(glval) = VariableAddress[i] : # 9| r9_2(Int32) = Constant[0] : @@ -1416,16 +1339,15 @@ pointers.cs: #-----| Goto -> Block 2 # 3| Block 1 -# 3| v3_6(Void) = ReturnVoid : -# 3| v3_7(Void) = UnmodeledUse : mu* -# 3| v3_8(Void) = AliasedUse : ~mu3_3 -# 3| v3_9(Void) = ExitFunction : +# 3| v3_5(Void) = ReturnVoid : +# 3| v3_6(Void) = AliasedUse : ~m? +# 3| v3_7(Void) = ExitFunction : # 9| Block 2 # 9| r9_4(glval) = VariableAddress[i] : -# 9| r9_5(Int32) = Load : &:r9_4, ~mu3_3 +# 9| r9_5(Int32) = Load : &:r9_4, ~m? # 9| r9_6(glval) = VariableAddress[length] : -# 9| r9_7(Int32) = Load : &:r9_6, ~mu3_3 +# 9| r9_7(Int32) = Load : &:r9_6, ~m? # 9| r9_8(Boolean) = CompareLT : r9_5, r9_7 # 9| v9_9(Void) = ConditionalBranch : r9_8 #-----| False -> Block 1 @@ -1434,15 +1356,15 @@ pointers.cs: # 10| Block 3 # 10| r10_1(Int32) = Constant[1] : # 10| r10_2(glval) = VariableAddress[p] : -# 10| r10_3(Int32*) = Load : &:r10_2, ~mu3_3 +# 10| r10_3(Int32*) = Load : &:r10_2, ~m? # 10| r10_4(Int32) = Constant[1] : # 10| r10_5(Int32*) = PointerAdd[4] : r10_3, r10_4 # 10| mu10_6(Int32*) = Store : &:r10_2, r10_5 -# 10| r10_7(Int32) = Load : &:r10_3, ~mu3_3 +# 10| r10_7(Int32) = Load : &:r10_3, ~m? # 10| r10_8(Int32) = Add : r10_7, r10_1 # 10| mu10_9(Int32) = Store : &:r10_3, r10_8 # 9| r9_10(glval) = VariableAddress[i] : -# 9| r9_11(Int32) = Load : &:r9_10, ~mu3_3 +# 9| r9_11(Int32) = Load : &:r9_10, ~m? # 9| r9_12(Int32) = Constant[1] : # 9| r9_13(Int32) = Add : r9_11, r9_12 # 9| mu9_14(Int32) = Store : &:r9_10, r9_13 @@ -1452,45 +1374,44 @@ pointers.cs: # 25| Block 0 # 25| v25_1(Void) = EnterFunction : # 25| mu25_2() = AliasedDefinition : -# 25| mu25_3() = UnmodeledDefinition : # 26| r26_1(glval) = VariableAddress[o] : # 26| r26_2(MyClass) = NewObj : # 26| r26_3() = FunctionAddress[MyClass] : # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu25_3 +# 26| mu26_5() = ^CallSideEffect : ~m? # 26| mu26_6(MyClass) = Store : &:r26_1, r26_2 # 27| r27_1(glval) = VariableAddress[s] : # 27| r27_2(MyStruct) = NewObj : # 27| r27_3() = FunctionAddress[MyStruct] : # 27| v27_4(Void) = Call : func:r27_3, this:r27_2 -# 27| mu27_5() = ^CallSideEffect : ~mu25_3 -# 27| r27_6(MyStruct) = Load : &:r27_2, ~mu25_3 +# 27| mu27_5() = ^CallSideEffect : ~m? +# 27| r27_6(MyStruct) = Load : &:r27_2, ~m? # 27| mu27_7(MyStruct) = Store : &:r27_1, r27_6 # 30| r30_1(glval) = VariableAddress[p] : # 30| r30_2(glval) = VariableAddress[o] : -# 30| r30_3(MyClass) = Load : &:r30_2, ~mu25_3 +# 30| r30_3(MyClass) = Load : &:r30_2, ~m? # 30| r30_4(glval) = FieldAddress[fld1] : r30_3 # 30| mu30_5(Int32*) = Store : &:r30_1, r30_4 # 30| r30_6(glval) = VariableAddress[q] : # 30| r30_7(glval) = VariableAddress[o] : -# 30| r30_8(MyClass) = Load : &:r30_7, ~mu25_3 +# 30| r30_8(MyClass) = Load : &:r30_7, ~m? # 30| r30_9(glval) = FieldAddress[fld2] : r30_8 # 30| mu30_10(Int32*) = Store : &:r30_6, r30_9 # 32| r32_1(Int32) = Constant[0] : # 32| r32_2(glval) = VariableAddress[p] : -# 32| r32_3(Int32*) = Load : &:r32_2, ~mu25_3 +# 32| r32_3(Int32*) = Load : &:r32_2, ~m? # 32| mu32_4(Int32) = Store : &:r32_3, r32_1 # 33| r33_1(Int32) = Constant[0] : # 33| r33_2(glval) = VariableAddress[q] : -# 33| r33_3(Int32*) = Load : &:r33_2, ~mu25_3 +# 33| r33_3(Int32*) = Load : &:r33_2, ~m? # 33| mu33_4(Int32) = Store : &:r33_3, r33_1 # 34| r34_1(glval) = VariableAddress[r] : # 34| r34_2(glval) = VariableAddress[s] : # 34| mu34_3(MyStruct*) = Store : &:r34_1, r34_2 # 35| r35_1(Int32) = Constant[0] : # 35| r35_2(glval) = VariableAddress[r] : -# 35| r35_3(MyStruct*) = Load : &:r35_2, ~mu25_3 -# 35| r35_4(MyStruct) = Load : &:r35_3, ~mu25_3 +# 35| r35_3(MyStruct*) = Load : &:r35_2, ~m? +# 35| r35_4(MyStruct) = Load : &:r35_3, ~m? # 35| r35_5(glval) = FieldAddress[fld] : r35_4 # 35| mu35_6(Int32) = Store : &:r35_5, r35_1 # 39| r39_1(glval) = VariableAddress[arr] : @@ -1509,151 +1430,135 @@ pointers.cs: # 39| mu39_14(Int32) = Store : &:r39_12, r39_13 # 40| r40_1() = FunctionAddress[addone] : # 40| r40_2(glval) = VariableAddress[arr] : -# 40| r40_3(Int32[]) = Load : &:r40_2, ~mu25_3 +# 40| r40_3(Int32[]) = Load : &:r40_2, ~m? # 40| v40_4(Void) = Call : func:r40_1, 0:r40_3 -# 40| mu40_5() = ^CallSideEffect : ~mu25_3 -# 25| v25_4(Void) = ReturnVoid : -# 25| v25_5(Void) = UnmodeledUse : mu* -# 25| v25_6(Void) = AliasedUse : ~mu25_3 -# 25| v25_7(Void) = ExitFunction : +# 40| mu40_5() = ^CallSideEffect : ~m? +# 25| v25_3(Void) = ReturnVoid : +# 25| v25_4(Void) = AliasedUse : ~m? +# 25| v25_5(Void) = ExitFunction : prop.cs: # 7| System.Int32 PropClass.get_Prop() # 7| Block 0 # 7| v7_1(Void) = EnterFunction : # 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : +# 7| r7_3(glval) = InitializeThis : # 9| r9_1(glval) = VariableAddress[#return] : -# 9| r9_2(PropClass) = CopyValue : r7_4 +# 9| r9_2(PropClass) = CopyValue : r7_3 # 9| r9_3() = FunctionAddress[func] : # 9| r9_4(Int32) = Call : func:r9_3, this:r9_2 -# 9| mu9_5() = ^CallSideEffect : ~mu7_3 +# 9| mu9_5() = ^CallSideEffect : ~m? # 9| mu9_6(Int32) = Store : &:r9_1, r9_4 -# 7| r7_5(glval) = VariableAddress[#return] : -# 7| v7_6(Void) = ReturnValue : &:r7_5, ~mu7_3 -# 7| v7_7(Void) = UnmodeledUse : mu* -# 7| v7_8(Void) = AliasedUse : ~mu7_3 -# 7| v7_9(Void) = ExitFunction : +# 7| r7_4(glval) = VariableAddress[#return] : +# 7| v7_5(Void) = ReturnValue : &:r7_4, ~m? +# 7| v7_6(Void) = AliasedUse : ~m? +# 7| v7_7(Void) = ExitFunction : # 12| System.Void PropClass.set_Prop(System.Int32) # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : -# 12| r12_4(glval) = InitializeThis : -# 12| r12_5(glval) = VariableAddress[value] : -# 12| mu12_6(Int32) = InitializeParameter[value] : &:r12_5 +# 12| r12_3(glval) = InitializeThis : +# 12| r12_4(glval) = VariableAddress[value] : +# 12| mu12_5(Int32) = InitializeParameter[value] : &:r12_4 # 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(Int32) = Load : &:r14_1, ~mu12_3 +# 14| r14_2(Int32) = Load : &:r14_1, ~m? # 14| r14_3(glval) = VariableAddress[prop] : # 14| mu14_4(Int32) = Store : &:r14_3, r14_2 -# 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = UnmodeledUse : mu* -# 12| v12_9(Void) = AliasedUse : ~mu12_3 -# 12| v12_10(Void) = ExitFunction : +# 12| v12_6(Void) = ReturnVoid : +# 12| v12_7(Void) = AliasedUse : ~m? +# 12| v12_8(Void) = ExitFunction : # 18| System.Int32 PropClass.func() # 18| Block 0 # 18| v18_1(Void) = EnterFunction : # 18| mu18_2() = AliasedDefinition : -# 18| mu18_3() = UnmodeledDefinition : -# 18| r18_4(glval) = InitializeThis : +# 18| r18_3(glval) = InitializeThis : # 20| r20_1(glval) = VariableAddress[#return] : # 20| r20_2(Int32) = Constant[0] : # 20| mu20_3(Int32) = Store : &:r20_1, r20_2 -# 18| r18_5(glval) = VariableAddress[#return] : -# 18| v18_6(Void) = ReturnValue : &:r18_5, ~mu18_3 -# 18| v18_7(Void) = UnmodeledUse : mu* -# 18| v18_8(Void) = AliasedUse : ~mu18_3 -# 18| v18_9(Void) = ExitFunction : +# 18| r18_4(glval) = VariableAddress[#return] : +# 18| v18_5(Void) = ReturnValue : &:r18_4, ~m? +# 18| v18_6(Void) = AliasedUse : ~m? +# 18| v18_7(Void) = ExitFunction : # 26| System.Void Prog.Main() # 26| Block 0 # 26| v26_1(Void) = EnterFunction : # 26| mu26_2() = AliasedDefinition : -# 26| mu26_3() = UnmodeledDefinition : # 28| r28_1(glval) = VariableAddress[obj] : # 28| r28_2(PropClass) = NewObj : # 28| r28_3() = FunctionAddress[PropClass] : # 28| v28_4(Void) = Call : func:r28_3, this:r28_2 -# 28| mu28_5() = ^CallSideEffect : ~mu26_3 +# 28| mu28_5() = ^CallSideEffect : ~m? # 28| mu28_6(PropClass) = Store : &:r28_1, r28_2 # 29| r29_1(glval) = VariableAddress[obj] : -# 29| r29_2(PropClass) = Load : &:r29_1, ~mu26_3 +# 29| r29_2(PropClass) = Load : &:r29_1, ~m? # 29| r29_3() = FunctionAddress[set_Prop] : # 29| r29_4(Int32) = Constant[5] : # 29| v29_5(Void) = Call : func:r29_3, this:r29_2, 0:r29_4 -# 29| mu29_6() = ^CallSideEffect : ~mu26_3 +# 29| mu29_6() = ^CallSideEffect : ~m? # 30| r30_1(glval) = VariableAddress[x] : # 30| r30_2(glval) = VariableAddress[obj] : -# 30| r30_3(PropClass) = Load : &:r30_2, ~mu26_3 +# 30| r30_3(PropClass) = Load : &:r30_2, ~m? # 30| r30_4() = FunctionAddress[get_Prop] : # 30| r30_5(Int32) = Call : func:r30_4, this:r30_3 -# 30| mu30_6() = ^CallSideEffect : ~mu26_3 +# 30| mu30_6() = ^CallSideEffect : ~m? # 30| mu30_7(Int32) = Store : &:r30_1, r30_5 -# 26| v26_4(Void) = ReturnVoid : -# 26| v26_5(Void) = UnmodeledUse : mu* -# 26| v26_6(Void) = AliasedUse : ~mu26_3 -# 26| v26_7(Void) = ExitFunction : +# 26| v26_3(Void) = ReturnVoid : +# 26| v26_4(Void) = AliasedUse : ~m? +# 26| v26_5(Void) = ExitFunction : simple_call.cs: # 5| System.Int32 test_simple_call.f() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 -# 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| r5_3(glval) = VariableAddress[#return] : +# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : # 10| System.Int32 test_simple_call.g() # 10| Block 0 # 10| v10_1(Void) = EnterFunction : # 10| mu10_2() = AliasedDefinition : -# 10| mu10_3() = UnmodeledDefinition : -# 10| r10_4(glval) = InitializeThis : +# 10| r10_3(glval) = InitializeThis : # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2() = FunctionAddress[f] : # 12| r12_3(Int32) = Call : func:r12_2 -# 12| mu12_4() = ^CallSideEffect : ~mu10_3 +# 12| mu12_4() = ^CallSideEffect : ~m? # 12| mu12_5(Int32) = Store : &:r12_1, r12_3 -# 10| r10_5(glval) = VariableAddress[#return] : -# 10| v10_6(Void) = ReturnValue : &:r10_5, ~mu10_3 -# 10| v10_7(Void) = UnmodeledUse : mu* -# 10| v10_8(Void) = AliasedUse : ~mu10_3 -# 10| v10_9(Void) = ExitFunction : +# 10| r10_4(glval) = VariableAddress[#return] : +# 10| v10_5(Void) = ReturnValue : &:r10_4, ~m? +# 10| v10_6(Void) = AliasedUse : ~m? +# 10| v10_7(Void) = ExitFunction : simple_function.cs: # 5| System.Int32 test_simple_function.f() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 -# 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| r5_3(glval) = VariableAddress[#return] : +# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : stmts.cs: # 5| System.Int32 test_stmts.ifStmt(System.Int32) # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = VariableAddress[x] : -# 5| mu5_5(Int32) = InitializeParameter[x] : &:r5_4 +# 5| r5_3(glval) = VariableAddress[x] : +# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 # 7| r7_1(glval) = VariableAddress[x] : -# 7| r7_2(Int32) = Load : &:r7_1, ~mu5_3 +# 7| r7_2(Int32) = Load : &:r7_1, ~m? # 7| r7_3(Int32) = Constant[5] : # 7| r7_4(Boolean) = CompareEQ : r7_2, r7_3 # 7| v7_5(Void) = ConditionalBranch : r7_4 @@ -1661,11 +1566,10 @@ stmts.cs: #-----| True -> Block 3 # 5| Block 1 -# 5| r5_6(glval) = VariableAddress[#return] : -# 5| v5_7(Void) = ReturnValue : &:r5_6, ~mu5_3 -# 5| v5_8(Void) = UnmodeledUse : mu* -# 5| v5_9(Void) = AliasedUse : ~mu5_3 -# 5| v5_10(Void) = ExitFunction : +# 5| r5_5(glval) = VariableAddress[#return] : +# 5| v5_6(Void) = ReturnValue : &:r5_5, ~m? +# 5| v5_7(Void) = AliasedUse : ~m? +# 5| v5_8(Void) = ExitFunction : # 10| Block 2 # 10| r10_1(glval) = VariableAddress[#return] : @@ -1683,23 +1587,21 @@ stmts.cs: # 13| Block 0 # 13| v13_1(Void) = EnterFunction : # 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = VariableAddress[x] : -# 13| mu13_5(Int32) = InitializeParameter[x] : &:r13_4 +# 13| r13_3(glval) = VariableAddress[x] : +# 13| mu13_4(Int32) = InitializeParameter[x] : &:r13_3 # 15| r15_1(glval) = VariableAddress[i] : # 15| r15_2(Int32) = Constant[0] : # 15| mu15_3(Int32) = Store : &:r15_1, r15_2 #-----| Goto -> Block 2 # 13| Block 1 -# 13| v13_6(Void) = ReturnVoid : -# 13| v13_7(Void) = UnmodeledUse : mu* -# 13| v13_8(Void) = AliasedUse : ~mu13_3 -# 13| v13_9(Void) = ExitFunction : +# 13| v13_5(Void) = ReturnVoid : +# 13| v13_6(Void) = AliasedUse : ~m? +# 13| v13_7(Void) = ExitFunction : # 16| Block 2 # 16| r16_1(glval) = VariableAddress[i] : -# 16| r16_2(Int32) = Load : &:r16_1, ~mu13_3 +# 16| r16_2(Int32) = Load : &:r16_1, ~m? # 16| r16_3(Int32) = Constant[10] : # 16| r16_4(Boolean) = CompareLT : r16_2, r16_3 # 16| v16_5(Void) = ConditionalBranch : r16_4 @@ -1708,7 +1610,7 @@ stmts.cs: # 18| Block 3 # 18| r18_1(glval) = VariableAddress[x] : -# 18| r18_2(Int32) = Load : &:r18_1, ~mu13_3 +# 18| r18_2(Int32) = Load : &:r18_1, ~m? # 18| r18_3(Int32) = Constant[1] : # 18| r18_4(Int32) = Add : r18_2, r18_3 # 18| r18_5(glval) = VariableAddress[x] : @@ -1719,18 +1621,17 @@ stmts.cs: # 22| Block 0 # 22| v22_1(Void) = EnterFunction : # 22| mu22_2() = AliasedDefinition : -# 22| mu22_3() = UnmodeledDefinition : # 24| r24_1(glval) = VariableAddress[caseSwitch] : # 24| r24_2(Object) = NewObj : # 24| r24_3() = FunctionAddress[Object] : # 24| v24_4(Void) = Call : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~mu22_3 +# 24| mu24_5() = ^CallSideEffect : ~m? # 24| mu24_6(Object) = Store : &:r24_1, r24_2 # 25| r25_1(glval) = VariableAddress[select] : # 25| r25_2(Int32) = Constant[0] : # 25| mu25_3(Int32) = Store : &:r25_1, r25_2 # 27| r27_1(glval) = VariableAddress[caseSwitch] : -# 27| r27_2(Object) = Load : &:r27_1, ~mu22_3 +# 27| r27_2(Object) = Load : &:r27_1, ~m? # 27| v27_3(Void) = Switch : r27_2 #-----| Case[-1] -> Block 2 #-----| Case[0] -> Block 3 @@ -1739,11 +1640,10 @@ stmts.cs: #-----| Default -> Block 6 # 22| Block 1 -# 22| r22_4(glval) = VariableAddress[#return] : -# 22| v22_5(Void) = ReturnValue : &:r22_4, ~mu22_3 -# 22| v22_6(Void) = UnmodeledUse : mu* -# 22| v22_7(Void) = AliasedUse : ~mu22_3 -# 22| v22_8(Void) = ExitFunction : +# 22| r22_3(glval) = VariableAddress[#return] : +# 22| v22_4(Void) = ReturnValue : &:r22_3, ~m? +# 22| v22_5(Void) = AliasedUse : ~m? +# 22| v22_6(Void) = ExitFunction : # 29| Block 2 # 29| v29_1(Void) = NoOp : @@ -1778,33 +1678,31 @@ stmts.cs: # 39| v39_1(Void) = NoOp : # 40| r40_1(glval) = VariableAddress[#return] : # 40| r40_2(glval) = VariableAddress[select] : -# 40| r40_3(Int32) = Load : &:r40_2, ~mu22_3 +# 40| r40_3(Int32) = Load : &:r40_2, ~m? # 40| mu40_4(Int32) = Store : &:r40_1, r40_3 #-----| Goto -> Block 1 # 46| System.Void test_stmts.tryCatchFinally() # 46| Block 0 -# 46| v46_1(Void) = EnterFunction : -# 46| mu46_2() = AliasedDefinition : -# 46| mu46_3() = UnmodeledDefinition : -# 48| r48_1(glval) = VariableAddress[x] : -# 48| r48_2(Int32) = Constant[5] : -# 48| mu48_3(Int32) = Store : &:r48_1, r48_2 -# 51| r51_1(glval) = VariableAddress[x] : -# 51| r51_2(Int32) = Load : &:r51_1, ~mu46_3 -# 51| r51_3(Int32) = Constant[0] : -# 51| r51_4(Boolean) = CompareNE : r51_2, r51_3 -# 51| v51_5(Void) = ConditionalBranch : r51_4 +# 46| v46_1(Void) = EnterFunction : +# 46| mu46_2() = AliasedDefinition : +# 48| r48_1(glval) = VariableAddress[x] : +# 48| r48_2(Int32) = Constant[5] : +# 48| mu48_3(Int32) = Store : &:r48_1, r48_2 +# 51| r51_1(glval) = VariableAddress[x] : +# 51| r51_2(Int32) = Load : &:r51_1, ~m? +# 51| r51_3(Int32) = Constant[0] : +# 51| r51_4(Boolean) = CompareNE : r51_2, r51_3 +# 51| v51_5(Void) = ConditionalBranch : r51_4 #-----| False -> Block 4 #-----| True -> Block 3 # 46| Block 1 -# 46| v46_4(Void) = UnmodeledUse : mu* -# 46| v46_5(Void) = AliasedUse : ~mu46_3 -# 46| v46_6(Void) = ExitFunction : +# 46| v46_3(Void) = AliasedUse : ~m? +# 46| v46_4(Void) = ExitFunction : # 46| Block 2 -# 46| v46_7(Void) = Unwind : +# 46| v46_5(Void) = Unwind : #-----| Goto -> Block 1 # 52| Block 3 @@ -1812,9 +1710,9 @@ stmts.cs: # 52| r52_2(Exception) = NewObj : # 52| r52_3() = FunctionAddress[Exception] : # 52| v52_4(Void) = Call : func:r52_3, this:r52_2 -# 52| mu52_5() = ^CallSideEffect : ~mu46_3 +# 52| mu52_5() = ^CallSideEffect : ~m? # 52| mu52_6(Exception) = Store : &:r52_1, r52_2 -# 52| v52_7(Void) = ThrowValue : &:r52_1, ~mu46_3 +# 52| v52_7(Void) = ThrowValue : &:r52_1, ~m? #-----| Exception -> Block 6 # 53| Block 4 @@ -1827,7 +1725,7 @@ stmts.cs: # 65| r65_1(Int32) = Constant[2] : # 65| r65_2(glval) = VariableAddress[x] : # 65| mu65_3(Int32) = Store : &:r65_2, r65_1 -# 46| v46_8(Void) = ReturnVoid : +# 46| v46_6(Void) = ReturnVoid : #-----| Goto -> Block 1 # 55| Block 6 @@ -1850,31 +1748,29 @@ stmts.cs: # 69| System.Void test_stmts.forStmt() # 69| Block 0 -# 69| v69_1(Void) = EnterFunction : -# 69| mu69_2() = AliasedDefinition : -# 69| mu69_3() = UnmodeledDefinition : -# 71| r71_1(glval) = VariableAddress[x] : -# 71| r71_2(Int32) = Constant[0] : -# 71| mu71_3(Int32) = Store : &:r71_1, r71_2 -# 72| r72_1(glval) = VariableAddress[i] : -# 72| r72_2(Int32) = Constant[0] : -# 72| mu72_3(Int32) = Store : &:r72_1, r72_2 -# 72| r72_4(glval) = VariableAddress[j] : -# 72| r72_5(Int32) = Constant[10] : -# 72| mu72_6(Int32) = Store : &:r72_4, r72_5 +# 69| v69_1(Void) = EnterFunction : +# 69| mu69_2() = AliasedDefinition : +# 71| r71_1(glval) = VariableAddress[x] : +# 71| r71_2(Int32) = Constant[0] : +# 71| mu71_3(Int32) = Store : &:r71_1, r71_2 +# 72| r72_1(glval) = VariableAddress[i] : +# 72| r72_2(Int32) = Constant[0] : +# 72| mu72_3(Int32) = Store : &:r72_1, r72_2 +# 72| r72_4(glval) = VariableAddress[j] : +# 72| r72_5(Int32) = Constant[10] : +# 72| mu72_6(Int32) = Store : &:r72_4, r72_5 #-----| Goto -> Block 2 # 69| Block 1 -# 69| v69_4(Void) = ReturnVoid : -# 69| v69_5(Void) = UnmodeledUse : mu* -# 69| v69_6(Void) = AliasedUse : ~mu69_3 -# 69| v69_7(Void) = ExitFunction : +# 69| v69_3(Void) = ReturnVoid : +# 69| v69_4(Void) = AliasedUse : ~m? +# 69| v69_5(Void) = ExitFunction : # 72| Block 2 # 72| r72_7(glval) = VariableAddress[i] : -# 72| r72_8(Int32) = Load : &:r72_7, ~mu69_3 +# 72| r72_8(Int32) = Load : &:r72_7, ~m? # 72| r72_9(glval) = VariableAddress[j] : -# 72| r72_10(Int32) = Load : &:r72_9, ~mu69_3 +# 72| r72_10(Int32) = Load : &:r72_9, ~m? # 72| r72_11(Boolean) = CompareLT : r72_8, r72_10 # 72| v72_12(Void) = ConditionalBranch : r72_11 #-----| False -> Block 4 @@ -1882,18 +1778,18 @@ stmts.cs: # 74| Block 3 # 74| r74_1(glval) = VariableAddress[x] : -# 74| r74_2(Int32) = Load : &:r74_1, ~mu69_3 +# 74| r74_2(Int32) = Load : &:r74_1, ~m? # 74| r74_3(Int32) = Constant[1] : # 74| r74_4(Int32) = Sub : r74_2, r74_3 # 74| r74_5(glval) = VariableAddress[x] : # 74| mu74_6(Int32) = Store : &:r74_5, r74_4 # 72| r72_13(glval) = VariableAddress[i] : -# 72| r72_14(Int32) = Load : &:r72_13, ~mu69_3 +# 72| r72_14(Int32) = Load : &:r72_13, ~m? # 72| r72_15(Int32) = Constant[1] : # 72| r72_16(Int32) = Add : r72_14, r72_15 # 72| mu72_17(Int32) = Store : &:r72_13, r72_16 # 72| r72_18(glval) = VariableAddress[j] : -# 72| r72_19(Int32) = Load : &:r72_18, ~mu69_3 +# 72| r72_19(Int32) = Load : &:r72_18, ~m? # 72| r72_20(Int32) = Constant[1] : # 72| r72_21(Int32) = Sub : r72_19, r72_20 # 72| mu72_22(Int32) = Store : &:r72_18, r72_21 @@ -1912,9 +1808,9 @@ stmts.cs: # 78| Block 5 # 78| r78_4(glval) = VariableAddress[a] : -# 78| r78_5(Int32) = Load : &:r78_4, ~mu69_3 +# 78| r78_5(Int32) = Load : &:r78_4, ~m? # 78| r78_6(glval) = VariableAddress[b] : -# 78| r78_7(Int32) = Load : &:r78_6, ~mu69_3 +# 78| r78_7(Int32) = Load : &:r78_6, ~m? # 78| r78_8(Boolean) = CompareLT : r78_5, r78_7 # 78| v78_9(Void) = ConditionalBranch : r78_8 #-----| False -> Block 7 @@ -1922,7 +1818,7 @@ stmts.cs: # 80| Block 6 # 80| r80_1(glval) = VariableAddress[a] : -# 80| r80_2(Int32) = Load : &:r80_1, ~mu69_3 +# 80| r80_2(Int32) = Load : &:r80_1, ~m? # 80| r80_3(Int32) = Constant[1] : # 80| r80_4(Int32) = Add : r80_2, r80_3 # 80| mu80_5(Int32) = Store : &:r80_1, r80_4 @@ -1934,29 +1830,27 @@ stmts.cs: # 89| System.Void test_stmts.doWhile() # 89| Block 0 -# 89| v89_1(Void) = EnterFunction : -# 89| mu89_2() = AliasedDefinition : -# 89| mu89_3() = UnmodeledDefinition : -# 91| r91_1(glval) = VariableAddress[x] : -# 91| r91_2(Int32) = Constant[0] : -# 91| mu91_3(Int32) = Store : &:r91_1, r91_2 +# 89| v89_1(Void) = EnterFunction : +# 89| mu89_2() = AliasedDefinition : +# 91| r91_1(glval) = VariableAddress[x] : +# 91| r91_2(Int32) = Constant[0] : +# 91| mu91_3(Int32) = Store : &:r91_1, r91_2 #-----| Goto -> Block 2 # 89| Block 1 -# 89| v89_4(Void) = ReturnVoid : -# 89| v89_5(Void) = UnmodeledUse : mu* -# 89| v89_6(Void) = AliasedUse : ~mu89_3 -# 89| v89_7(Void) = ExitFunction : +# 89| v89_3(Void) = ReturnVoid : +# 89| v89_4(Void) = AliasedUse : ~m? +# 89| v89_5(Void) = ExitFunction : # 94| Block 2 # 94| r94_1(glval) = VariableAddress[x] : -# 94| r94_2(Int32) = Load : &:r94_1, ~mu89_3 +# 94| r94_2(Int32) = Load : &:r94_1, ~m? # 94| r94_3(Int32) = Constant[1] : # 94| r94_4(Int32) = Add : r94_2, r94_3 # 94| r94_5(glval) = VariableAddress[x] : # 94| mu94_6(Int32) = Store : &:r94_5, r94_4 # 96| r96_1(glval) = VariableAddress[x] : -# 96| r96_2(Int32) = Load : &:r96_1, ~mu89_3 +# 96| r96_2(Int32) = Load : &:r96_1, ~m? # 96| r96_3(Int32) = Constant[10] : # 96| r96_4(Boolean) = CompareLT : r96_2, r96_3 # 96| v96_5(Void) = ConditionalBranch : r96_4 @@ -1967,131 +1861,119 @@ stmts.cs: # 99| Block 0 # 99| v99_1(Void) = EnterFunction : # 99| mu99_2() = AliasedDefinition : -# 99| mu99_3() = UnmodeledDefinition : # 101| r101_1(glval) = VariableAddress[num] : # 101| r101_2(Int32) = Constant[2147483647] : -# 101| r101_3(Int32) = Load : &:r101_2, ~mu99_3 +# 101| r101_3(Int32) = Load : &:r101_2, ~m? # 101| mu101_4(Int32) = Store : &:r101_1, r101_3 # 104| r104_1(glval) = VariableAddress[num] : -# 104| r104_2(Int32) = Load : &:r104_1, ~mu99_3 +# 104| r104_2(Int32) = Load : &:r104_1, ~m? # 104| r104_3(Int32) = Constant[1] : # 104| r104_4(Int32) = Add : r104_2, r104_3 # 104| r104_5(glval) = VariableAddress[num] : # 104| mu104_6(Int32) = Store : &:r104_5, r104_4 # 108| r108_1(glval) = VariableAddress[num] : -# 108| r108_2(Int32) = Load : &:r108_1, ~mu99_3 +# 108| r108_2(Int32) = Load : &:r108_1, ~m? # 108| r108_3(Int32) = Constant[1] : # 108| r108_4(Int32) = Add : r108_2, r108_3 # 108| r108_5(glval) = VariableAddress[num] : # 108| mu108_6(Int32) = Store : &:r108_5, r108_4 -# 99| v99_4(Void) = ReturnVoid : -# 99| v99_5(Void) = UnmodeledUse : mu* -# 99| v99_6(Void) = AliasedUse : ~mu99_3 -# 99| v99_7(Void) = ExitFunction : +# 99| v99_3(Void) = ReturnVoid : +# 99| v99_4(Void) = AliasedUse : ~m? +# 99| v99_5(Void) = ExitFunction : using.cs: # 7| System.Void UsingStmt.MyDisposable..ctor() # 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : -# 7| v7_5(Void) = NoOp : -# 7| v7_6(Void) = ReturnVoid : -# 7| v7_7(Void) = UnmodeledUse : mu* -# 7| v7_8(Void) = AliasedUse : ~mu7_3 -# 7| v7_9(Void) = ExitFunction : +# 7| v7_1(Void) = EnterFunction : +# 7| mu7_2() = AliasedDefinition : +# 7| r7_3(glval) = InitializeThis : +# 7| v7_4(Void) = NoOp : +# 7| v7_5(Void) = ReturnVoid : +# 7| v7_6(Void) = AliasedUse : ~m? +# 7| v7_7(Void) = ExitFunction : # 8| System.Void UsingStmt.MyDisposable.DoSomething() # 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : -# 8| v8_5(Void) = NoOp : -# 8| v8_6(Void) = ReturnVoid : -# 8| v8_7(Void) = UnmodeledUse : mu* -# 8| v8_8(Void) = AliasedUse : ~mu8_3 -# 8| v8_9(Void) = ExitFunction : +# 8| v8_1(Void) = EnterFunction : +# 8| mu8_2() = AliasedDefinition : +# 8| r8_3(glval) = InitializeThis : +# 8| v8_4(Void) = NoOp : +# 8| v8_5(Void) = ReturnVoid : +# 8| v8_6(Void) = AliasedUse : ~m? +# 8| v8_7(Void) = ExitFunction : # 9| System.Void UsingStmt.MyDisposable.Dispose() # 9| Block 0 -# 9| v9_1(Void) = EnterFunction : -# 9| mu9_2() = AliasedDefinition : -# 9| mu9_3() = UnmodeledDefinition : -# 9| r9_4(glval) = InitializeThis : -# 9| v9_5(Void) = NoOp : -# 9| v9_6(Void) = ReturnVoid : -# 9| v9_7(Void) = UnmodeledUse : mu* -# 9| v9_8(Void) = AliasedUse : ~mu9_3 -# 9| v9_9(Void) = ExitFunction : +# 9| v9_1(Void) = EnterFunction : +# 9| mu9_2() = AliasedDefinition : +# 9| r9_3(glval) = InitializeThis : +# 9| v9_4(Void) = NoOp : +# 9| v9_5(Void) = ReturnVoid : +# 9| v9_6(Void) = AliasedUse : ~m? +# 9| v9_7(Void) = ExitFunction : # 12| System.Void UsingStmt.Main() # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : # 14| r14_1(glval) = VariableAddress[o1] : # 14| r14_2(MyDisposable) = NewObj : # 14| r14_3() = FunctionAddress[MyDisposable] : # 14| v14_4(Void) = Call : func:r14_3, this:r14_2 -# 14| mu14_5() = ^CallSideEffect : ~mu12_3 +# 14| mu14_5() = ^CallSideEffect : ~m? # 14| mu14_6(MyDisposable) = Store : &:r14_1, r14_2 # 16| r16_1(glval) = VariableAddress[o1] : -# 16| r16_2(MyDisposable) = Load : &:r16_1, ~mu12_3 +# 16| r16_2(MyDisposable) = Load : &:r16_1, ~m? # 16| r16_3() = FunctionAddress[DoSomething] : # 16| v16_4(Void) = Call : func:r16_3, this:r16_2 -# 16| mu16_5() = ^CallSideEffect : ~mu12_3 +# 16| mu16_5() = ^CallSideEffect : ~m? # 19| r19_1(glval) = VariableAddress[o2] : # 19| r19_2(MyDisposable) = NewObj : # 19| r19_3() = FunctionAddress[MyDisposable] : # 19| v19_4(Void) = Call : func:r19_3, this:r19_2 -# 19| mu19_5() = ^CallSideEffect : ~mu12_3 +# 19| mu19_5() = ^CallSideEffect : ~m? # 19| mu19_6(MyDisposable) = Store : &:r19_1, r19_2 # 22| r22_1(glval) = VariableAddress[o2] : -# 22| r22_2(MyDisposable) = Load : &:r22_1, ~mu12_3 +# 22| r22_2(MyDisposable) = Load : &:r22_1, ~m? # 22| r22_3() = FunctionAddress[DoSomething] : # 22| v22_4(Void) = Call : func:r22_3, this:r22_2 -# 22| mu22_5() = ^CallSideEffect : ~mu12_3 +# 22| mu22_5() = ^CallSideEffect : ~m? # 25| r25_1(glval) = VariableAddress[o3] : # 25| r25_2(MyDisposable) = NewObj : # 25| r25_3() = FunctionAddress[MyDisposable] : # 25| v25_4(Void) = Call : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~mu12_3 +# 25| mu25_5() = ^CallSideEffect : ~m? # 25| mu25_6(MyDisposable) = Store : &:r25_1, r25_2 # 26| r26_1(glval) = VariableAddress[o3] : -# 26| r26_2(MyDisposable) = Load : &:r26_1, ~mu12_3 +# 26| r26_2(MyDisposable) = Load : &:r26_1, ~m? # 26| r26_3() = FunctionAddress[DoSomething] : # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu12_3 -# 12| v12_4(Void) = ReturnVoid : -# 12| v12_5(Void) = UnmodeledUse : mu* -# 12| v12_6(Void) = AliasedUse : ~mu12_3 -# 12| v12_7(Void) = ExitFunction : +# 26| mu26_5() = ^CallSideEffect : ~m? +# 12| v12_3(Void) = ReturnVoid : +# 12| v12_4(Void) = AliasedUse : ~m? +# 12| v12_5(Void) = ExitFunction : variables.cs: # 5| System.Void test_variables.f() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 7| r7_1(glval) = VariableAddress[x] : -# 7| mu7_2(Int32) = Uninitialized[x] : &:r7_1 -# 7| r7_3(glval) = VariableAddress[y] : -# 7| r7_4(Int32) = Constant[5] : -# 7| mu7_5(Int32) = Store : &:r7_3, r7_4 -# 8| r8_1(Int32) = Constant[4] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| mu8_3(Int32) = Store : &:r8_2, r8_1 -# 9| r9_1(glval) = VariableAddress[y] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu5_3 -# 9| r9_3(glval) = VariableAddress[x] : -# 9| mu9_4(Int32) = Store : &:r9_3, r9_2 -# 10| r10_1(glval) = VariableAddress[z] : -# 10| r10_2(glval) = VariableAddress[y] : -# 10| r10_3(Int32) = Load : &:r10_2, ~mu5_3 -# 10| mu10_4(Int32) = Store : &:r10_1, r10_3 -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 7| r7_1(glval) = VariableAddress[x] : +# 7| mu7_2(Int32) = Uninitialized[x] : &:r7_1 +# 7| r7_3(glval) = VariableAddress[y] : +# 7| r7_4(Int32) = Constant[5] : +# 7| mu7_5(Int32) = Store : &:r7_3, r7_4 +# 8| r8_1(Int32) = Constant[4] : +# 8| r8_2(glval) = VariableAddress[x] : +# 8| mu8_3(Int32) = Store : &:r8_2, r8_1 +# 9| r9_1(glval) = VariableAddress[y] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(glval) = VariableAddress[x] : +# 9| mu9_4(Int32) = Store : &:r9_3, r9_2 +# 10| r10_1(glval) = VariableAddress[z] : +# 10| r10_2(glval) = VariableAddress[y] : +# 10| r10_3(Int32) = Load : &:r10_2, ~m? +# 10| mu10_4(Int32) = Store : &:r10_1, r10_3 +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref new file mode 100644 index 00000000000..336afc397f5 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected similarity index 95% rename from csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected index 61bc9b2261c..5d16b01eaca 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref new file mode 100644 index 00000000000..3059c9b7b77 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/simple_call.cs b/csharp/ql/test/experimental/ir/ir/simple_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_call.cs rename to csharp/ql/test/experimental/ir/ir/simple_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/simple_function.cs b/csharp/ql/test/experimental/ir/ir/simple_function.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_function.cs rename to csharp/ql/test/experimental/ir/ir/simple_function.cs diff --git a/csharp/ql/test/library-tests/ir/ir/stmts.cs b/csharp/ql/test/experimental/ir/ir/stmts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/stmts.cs rename to csharp/ql/test/experimental/ir/ir/stmts.cs diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected new file mode 100644 index 00000000000..5d16b01eaca --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected @@ -0,0 +1,27 @@ +missingOperand +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +duplicateChiOperand +sideEffectWithoutPrimary +instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop +unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge +notMarkedAsConflated +wronglyMarkedAsConflated +invalidOverlap +nonUniqueEnclosingIRFunction +missingCanonicalLanguageType +multipleCanonicalLanguageTypes +missingIRType +multipleIRTypes diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref new file mode 100644 index 00000000000..65c39482529 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected new file mode 100644 index 00000000000..21782bd5ef1 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected @@ -0,0 +1,3 @@ +multipleOperandMemoryLocations +missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref new file mode 100644 index 00000000000..8d24936ecea --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/using.cs b/csharp/ql/test/experimental/ir/ir/using.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/using.cs rename to csharp/ql/test/experimental/ir/ir/using.cs diff --git a/csharp/ql/test/library-tests/ir/ir/variables.cs b/csharp/ql/test/experimental/ir/ir/variables.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/variables.cs rename to csharp/ql/test/experimental/ir/ir/variables.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql similarity index 91% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql index 16ba1c861a1..7518386e6d2 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql +++ b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql @@ -1,7 +1,7 @@ import csharp -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.rangeanalysis.RangeUtils +import experimental.ir.IR +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.rangeanalysis.RangeUtils /** * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. diff --git a/csharp/ql/test/library-tests/ir/offbyone/null.cs b/csharp/ql/test/experimental/ir/offbyone/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/null.cs rename to csharp/ql/test/experimental/ir/offbyone/null.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/test.cs b/csharp/ql/test/experimental/ir/offbyone/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/test.cs rename to csharp/ql/test/experimental/ir/offbyone/test.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql similarity index 79% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql index 0eed018495a..ab62db5e5ff 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql +++ b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql @@ -1,7 +1,7 @@ -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.internal.IRGuards -import semmle.code.csharp.ir.ValueNumbering +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.IR +import experimental.ir.internal.IRGuards +import experimental.ir.ValueNumbering query predicate instructionBounds( Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs b/csharp/ql/test/experimental/ir/rangeanalysis/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/null.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/null.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs b/csharp/ql/test/experimental/ir/rangeanalysis/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/test.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/test.cs diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index a6baeb18564..44e01cd582f 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -59,6 +59,8 @@ | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | exit Typeof | 5 | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | exit Nameof | 5 | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | exit M | 14 | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | 1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | 2 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | 1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:28:3:38 | call to method ToString | 1 | @@ -84,7 +86,12 @@ | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | 1 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:43:19:60 | call to method CommaJoinWith | 2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | exit M7 | 17 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | 7 | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | 1 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | 1 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | 1 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | 7 | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | 1 | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | 6 | @@ -400,14 +407,15 @@ | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | exit M6 | 1 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | exit Initializers | 14 | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 14 | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | exit M | 20 | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | 2 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | exit NoConstructor | 8 | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | exit Sub | 11 | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 8 | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 18 | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 14 | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 20 | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | 2 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 8 | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 11 | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 8 | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 18 | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 104 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | 1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 4937b513ac9..de06a13ac4e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -53,6 +53,7 @@ conditionBlock | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:14:20:14:20 | 0 | true | | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:16:20:16:20 | 1 | false | | ConditionalAccess.cs:19:12:19:13 | enter M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | false | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | false | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | true | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:7:9:8:16 | [inc (line 3): false] if (...) ... | false | | Conditions.cs:11:9:11:10 | enter M1 | Conditions.cs:15:13:15:16 | [b (line 11): true] ...; | true | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs index 00743aba169..a03564b529f 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs @@ -24,6 +24,16 @@ class ConditionalAccess var s = ((int?)i)?.ToString(); s = ""?.CommaJoinWith(s); } + + ConditionalAccess Prop { get; set; } + + void Out(out int i) => i = 0; + + void M8(bool b, out int i) + { + i = 0; + Prop?.Out(out i); + } } static class Ext diff --git a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected index bccab8e85a4..2a17d4114b0 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected @@ -5,3 +5,5 @@ breakInvariant3 breakInvariant4 breakInvariant5 multipleSuccessors +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:30:10:30:12 | exit Out | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index a4fda4ea940..f2367ae6d06 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -477,6 +477,7 @@ dominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -523,12 +524,27 @@ dominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | @@ -1683,93 +1699,196 @@ dominance | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | -| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:17:12:53 | object creation of type Initializers | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:13:12:53 | Initializers i = ... | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:40:12:44 | ... = ... | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:47:12:51 | ... = ... | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:38:12:53 | { ..., ... } | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:47:12:47 | access to property G | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | exit M | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:37:13:63 | { ..., ... } | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:42:13:61 | object creation of type Initializers | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | exit Sub | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:30 | ... = ... | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:35 | ... = ... | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | exit Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:17:14:53 | object creation of type Initializers | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:13:14:53 | Initializers i = ... | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:40:14:44 | ... = ... | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:37:15:63 | { ..., ... } | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:42:15:61 | object creation of type Initializers | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | exit NoConstructor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:30 | ... = ... | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:35 | ... = ... | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | exit Sub | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:29:35:37 | ... = ... | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:37 | ... + ... | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:84 | ... + ... | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:65 | ... + ... | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:69 | ... + ... | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:47 | ... + ... | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:33:62:33 | 1 | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:51 | ... + ... | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:49 | ... + ... | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:36:64:36 | 1 | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:54 | ... + ... | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | @@ -3429,6 +3548,8 @@ postDominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:9:40:11 | End: | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:38 | ...; | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:40:3:49 | call to method ToLower | @@ -3475,12 +3596,26 @@ postDominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:9:25:33 | ...; | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:13:25:14 | "" | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:70:31:83 | ... + ... | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:78 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:70:41:83 | ... + ... | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:78 | ... + ... | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:8:13:8:15 | ...-- | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | enter IncrOrDecr | @@ -4595,93 +4730,196 @@ postDominance | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:37:5:40:5 | {...} | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:18:38:34 | (..., ...) | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:6:5:6:16 | enter Initializers | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:10:10:10:10 | exit M | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:38:12:53 | { ..., ... } | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:47:12:51 | ... = ... | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:17:12:53 | object creation of type Initializers | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:47:12:47 | access to property G | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:40:12:44 | ... = ... | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:12:13:12:53 | Initializers i = ... | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:37:13:63 | { ..., ... } | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:42:13:61 | object creation of type Initializers | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:33:9:33:11 | enter Sub | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:29:9:29:11 | exit Sub | Initializers.cs:29:26:29:30 | ... = ... | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:9:29:11 | enter Sub | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:31:31:35 | ... = ... | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:9:31:11 | enter Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:29:33:37 | ... = ... | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:33:33:37 | ... + ... | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:37:33:37 | access to parameter j | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:33 | access to parameter i | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:8:5:8:16 | enter Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:10:5:10:16 | exit Initializers | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:12:10:12:10 | exit M | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:38:14:53 | { ..., ... } | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:47:14:51 | ... = ... | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:17:14:53 | object creation of type Initializers | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:47:14:47 | access to property G | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:40:14:44 | ... = ... | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:14:13:14:53 | Initializers i = ... | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:37:15:63 | { ..., ... } | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:42:15:61 | object creation of type Initializers | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | exit NoConstructor | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:20:11:20:23 | enter NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:26:31:30 | ... = ... | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:9:31:11 | enter Sub | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:31:33:35 | ... = ... | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:35:9:35:11 | exit Sub | Initializers.cs:35:29:35:37 | ... = ... | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:33:35:37 | ... + ... | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:51:10:51:13 | exit Test | Initializers.cs:57:13:65:9 | Compound compound = ... | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:51:10:51:13 | enter Test | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:50:54:95 | { ..., ... } | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:79:54:93 | ... = ... | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:54 | access to indexer | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:68 | access to indexer | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:85 | access to indexer | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:80:54:84 | ... + ... | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:54:13:54:95 | Dictionary dict = ... | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:58:9:65:9 | { ..., ... } | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:64:13:64:63 | ... = ... | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:60:59:74 | ... = ... | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:35 | access to indexer | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:49 | access to indexer | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:66 | access to indexer | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:61:59:65 | ... + ... | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:34:60:80 | { ..., ... } | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:64:60:78 | ... = ... | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:38 | access to indexer | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:53 | access to indexer | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:70 | access to indexer | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:65:60:69 | ... + ... | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:42:61:56 | ... = ... | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:43:61:47 | ... + ... | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:43:62:58 | ... = ... | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:33:62:33 | 1 | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:47:62:51 | ... + ... | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:29:63:60 | { ..., ... } | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:25 | access to property ArrayProperty | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:44:63:58 | ... = ... | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:45:63:49 | ... + ... | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:30:64:63 | { ..., ... } | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:46:64:61 | ... = ... | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:36:64:36 | 1 | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:32:64:43 | ... = ... | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:50:64:54 | ... + ... | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | enter M1 | @@ -5975,6 +6213,9 @@ blockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -6022,7 +6263,16 @@ blockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | @@ -7044,14 +7294,15 @@ blockDominance | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | enter NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | enter Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | @@ -8140,6 +8391,10 @@ postBlockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:10:30:12 | enter Out | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | @@ -8185,7 +8440,15 @@ postBlockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | @@ -8857,14 +9120,15 @@ postBlockDominance | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | enter NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | enter Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 0619257c9ed..4881b782090 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -508,6 +508,8 @@ nodeEnclosing | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -564,13 +566,31 @@ nodeEnclosing | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | IncrOrDecr | @@ -1813,99 +1833,203 @@ nodeEnclosing | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:36:10:36:11 | M6 | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:10:5:10:16 | Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | Initializers | | Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:10:10:10:10 | exit M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:9:29:11 | exit Sub | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:9:29:11 | Sub | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:10:5:10:16 | exit Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:12:10:12:10 | exit M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:20:11:20:23 | exit NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:35:9:35:11 | Sub | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | Sub | | Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:9:35:11 | exit Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:51:10:51:13 | exit Test | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:51:10:51:13 | Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | M1 | @@ -3257,6 +3381,8 @@ blockEnclosing | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -3282,7 +3408,12 @@ blockEnclosing | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:3:10:3:19 | IncrOrDecr | @@ -3598,13 +3729,14 @@ blockEnclosing | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:36:10:36:11 | M6 | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 9b9bfec2d27..6c20249d51d 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -493,11 +493,21 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:13:5:15 | access to parameter inc | Conditions.cs:5:13:5:15 | access to parameter inc | @@ -1226,74 +1236,181 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | -| Initializers.cs:3:9:3:9 | access to field F | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:18:13:63 | 2 | Initializers.cs:13:18:13:63 | 2 | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:20:23:20:23 | access to field F | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:21:23:21:23 | access to field G | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:26:13:26:13 | access to field H | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:29:26:29:26 | access to field I | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:31:31:31 | access to field I | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:33:29:33:29 | access to field I | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j | +| Initializers.cs:5:9:5:9 | access to field F | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | 2 | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:22:23:22:23 | access to field F | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:23:23:23:23 | access to field G | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:28:13:28:13 | access to field H | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:31:26:31:26 | access to field I | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:31:33:31 | access to field I | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:35:29:35:29 | access to field I | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:28:61:30 | access to array element | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:42:61:48 | access to array element | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:29:62:34 | access to array element | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:43:62:52 | access to array element | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:31:63:33 | access to array element | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:44:63:50 | access to array element | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:32:64:37 | access to array element | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:46:64:55 | access to array element | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:59:64:61 | "1" | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:9:10:19 | if (...) ... | | LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:16 | access to parameter args | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index 6d20b0e2271..2787a5ca6af 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -582,11 +582,25 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | normal | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | normal | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | normal | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:78 | ... + ... | normal | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:83 | ... + ... | normal | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | normal | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | normal | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:28:30:32 | ... = ... | normal | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | normal | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | normal | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | non-null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | normal | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | normal | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:78 | ... + ... | normal | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:83 | ... + ... | normal | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | normal | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | normal | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:7:14:7:16 | access to parameter inc | false [true] | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:8:13:8:15 | ...-- | normal | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | false | @@ -1720,74 +1734,181 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | normal | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | normal | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | normal | -| Initializers.cs:3:9:3:9 | access to field F | Initializers.cs:3:9:3:9 | this access | normal | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access | normal | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:17 | ... = ... | normal | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | normal | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:17 | ... + ... | normal | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | normal | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:9:4:9 | this access | normal | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access | normal | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:25:4:31 | ... = ... | normal | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | normal | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:31 | ... + ... | normal | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | normal | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:20:6:22 | {...} | normal | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:28:8:30 | {...} | normal | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:13:12:53 | Initializers i = ... | normal | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:13:12:53 | Initializers i = ... | normal | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:38:12:53 | { ..., ... } | normal | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:34:12:35 | "" | normal | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:38:12:53 | { ..., ... } | normal | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:40:12:44 | ... = ... | normal | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:44:12:44 | 0 | normal | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:47:12:51 | ... = ... | normal | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:51:12:51 | 1 | normal | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:13:18:13:63 | 2 | Initializers.cs:13:18:13:63 | 2 | normal | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:37:13:63 | { ..., ... } | normal | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:37:13:63 | { ..., ... } | normal | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:39:13:39 | access to local variable i | normal | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:42:13:61 | object creation of type Initializers | normal | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:59:13:60 | "" | normal | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:16:16:20 | ... = ... | normal | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | normal | -| Initializers.cs:20:23:20:23 | access to field F | Initializers.cs:20:23:20:23 | this access | normal | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:23:20:23 | this access | normal | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:23:20:27 | ... = ... | normal | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:27:20:27 | 0 | normal | -| Initializers.cs:21:23:21:23 | access to field G | Initializers.cs:21:23:21:23 | this access | normal | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:23:21:23 | this access | normal | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:23:21:27 | ... = ... | normal | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:27:21:27 | 1 | normal | -| Initializers.cs:26:13:26:13 | access to field H | Initializers.cs:26:13:26:13 | this access | normal | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:13:26:13 | this access | normal | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:13:26:17 | ... = ... | normal | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:17:26:17 | 2 | normal | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | normal | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:26:29:26 | access to field I | Initializers.cs:29:26:29:26 | this access | normal | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:26 | this access | normal | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:30:29:30 | 3 | normal | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | normal | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:31:31:31 | access to field I | Initializers.cs:31:31:31:31 | this access | normal | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:31 | this access | normal | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:35:31:35 | access to parameter i | normal | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:29:33:29 | access to field I | Initializers.cs:33:29:33:29 | this access | normal | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:29 | this access | normal | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i | normal | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:37 | ... + ... | normal | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j | normal | +| Initializers.cs:5:9:5:9 | access to field F | Initializers.cs:5:9:5:9 | this access | normal | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:9:5:9 | this access | normal | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:9:5:17 | ... = ... | normal | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:13:5:13 | access to field H | normal | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:13:5:17 | ... + ... | normal | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:17:5:17 | 1 | normal | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:9:6:9 | this access | normal | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:9:6:9 | this access | normal | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:25:6:31 | ... = ... | normal | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:27:6:27 | access to field H | normal | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:27:6:31 | ... + ... | normal | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:31:6:31 | 2 | normal | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:20:8:22 | {...} | normal | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:28:10:30 | {...} | normal | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:13:14:53 | Initializers i = ... | normal | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:13:14:53 | Initializers i = ... | normal | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:38:14:53 | { ..., ... } | normal | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:34:14:35 | "" | normal | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:38:14:53 | { ..., ... } | normal | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:40:14:44 | ... = ... | normal | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:44:14:44 | 0 | normal | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:47:14:51 | ... = ... | normal | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:51:14:51 | 1 | normal | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | 2 | normal | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:37:15:63 | { ..., ... } | normal | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:37:15:63 | { ..., ... } | normal | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:39:15:39 | access to local variable i | normal | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:42:15:61 | object creation of type Initializers | normal | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:59:15:60 | "" | normal | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:16:18:20 | ... = ... | normal | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | normal | +| Initializers.cs:22:23:22:23 | access to field F | Initializers.cs:22:23:22:23 | this access | normal | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:23:22:23 | this access | normal | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:23:22:27 | ... = ... | normal | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:27:22:27 | 0 | normal | +| Initializers.cs:23:23:23:23 | access to field G | Initializers.cs:23:23:23:23 | this access | normal | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:23:23:23 | this access | normal | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:23:23:27 | ... = ... | normal | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:27:23:27 | 1 | normal | +| Initializers.cs:28:13:28:13 | access to field H | Initializers.cs:28:13:28:13 | this access | normal | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:13:28:13 | this access | normal | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:13:28:17 | ... = ... | normal | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:17:28:17 | 2 | normal | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | normal | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:26:31:26 | access to field I | Initializers.cs:31:26:31:26 | this access | normal | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:26 | this access | normal | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:30:31:30 | 3 | normal | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | normal | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:31:33:31 | access to field I | Initializers.cs:33:31:33:31 | this access | normal | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:31 | this access | normal | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:35:33:35 | access to parameter i | normal | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:29:35:29 | access to field I | Initializers.cs:35:29:35:29 | this access | normal | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:29 | this access | normal | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:33:35:33 | access to parameter i | normal | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:33:35:37 | ... + ... | normal | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:37:35:37 | access to parameter j | normal | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:13:54:95 | Dictionary dict = ... | normal | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:13:54:95 | Dictionary dict = ... | normal | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:50:54:95 | { ..., ... } | normal | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:50:54:95 | { ..., ... } | normal | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:53:54:53 | 0 | normal | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:63 | ... = ... | normal | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | normal | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | normal | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:67:54:67 | 1 | normal | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:76 | ... = ... | normal | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | normal | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | normal | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:80:54:84 | ... + ... | normal | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:93 | ... = ... | normal | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | normal | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:84 | ... + ... | normal | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:84:54:84 | 2 | normal | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:89:54:93 | "Two" | normal | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:58:9:65:9 | { ..., ... } | normal | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:58:9:65:9 | { ..., ... } | normal | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:13:59:76 | ... = ... | normal | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:31:59:76 | { ..., ... } | normal | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:34:59:34 | 0 | normal | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:44 | ... = ... | normal | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | normal | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | normal | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:48:59:48 | 1 | normal | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:57 | ... = ... | normal | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | normal | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | normal | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:61:59:65 | ... + ... | normal | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:74 | ... = ... | normal | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | normal | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:65 | ... + ... | normal | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:65:59:65 | 2 | normal | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | normal | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:80 | ... = ... | normal | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:34:60:80 | { ..., ... } | normal | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:37:60:37 | 3 | normal | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:48 | ... = ... | normal | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | normal | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | normal | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:52:60:52 | 2 | normal | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:61 | ... = ... | normal | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | normal | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | normal | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:65:60:69 | ... + ... | normal | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:78 | ... = ... | normal | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | normal | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:69 | ... + ... | normal | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:69:60:69 | 1 | normal | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | normal | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:13:61:58 | ... = ... | normal | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:26:61:58 | { ..., ... } | normal | +| Initializers.cs:61:28:61:30 | access to array element | Initializers.cs:61:29:61:29 | 0 | normal | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:28:61:39 | ... = ... | normal | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | normal | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | normal | +| Initializers.cs:61:42:61:48 | access to array element | Initializers.cs:61:43:61:47 | ... + ... | normal | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:42:61:56 | ... = ... | normal | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | normal | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:47 | ... + ... | normal | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:47:61:47 | 1 | normal | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | normal | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:13:62:60 | ... = ... | normal | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:27:62:60 | { ..., ... } | normal | +| Initializers.cs:62:29:62:34 | access to array element | Initializers.cs:62:33:62:33 | 1 | normal | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:29:62:40 | ... = ... | normal | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | normal | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | normal | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | normal | +| Initializers.cs:62:43:62:52 | access to array element | Initializers.cs:62:47:62:51 | ... + ... | normal | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:43:62:58 | ... = ... | normal | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | normal | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | normal | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:47:62:51 | ... + ... | normal | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:51:62:51 | 0 | normal | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | normal | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:60 | ... = ... | normal | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:29:63:60 | { ..., ... } | normal | +| Initializers.cs:63:31:63:33 | access to array element | Initializers.cs:63:32:63:32 | 1 | normal | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:31:63:41 | ... = ... | normal | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | normal | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | normal | +| Initializers.cs:63:44:63:50 | access to array element | Initializers.cs:63:45:63:49 | ... + ... | normal | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:44:63:58 | ... = ... | normal | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | normal | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:49 | ... + ... | normal | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:49:63:49 | 2 | normal | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | normal | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:63 | ... = ... | normal | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:30:64:63 | { ..., ... } | normal | +| Initializers.cs:64:32:64:37 | access to array element | Initializers.cs:64:36:64:36 | 1 | normal | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:32:64:43 | ... = ... | normal | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | normal | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | normal | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | normal | +| Initializers.cs:64:46:64:55 | access to array element | Initializers.cs:64:50:64:54 | ... + ... | normal | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:46:64:61 | ... = ... | normal | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | normal | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | normal | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:50:64:54 | ... + ... | normal | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:54:64:54 | 0 | normal | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:59:64:61 | "1" | normal | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:10:13:10:19 | return ...; | return | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | empty | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:28 | ... == ... | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs index 1f690e778a4..2239b2f4723 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + class Initializers { int F = H + 1; @@ -33,3 +35,33 @@ class Initializers Sub(int i, int j) { I = i + j; } } } + +class IndexInitializers +{ + class Compound + { + public Dictionary DictionaryField; + public Dictionary DictionaryProperty { get; set; } + public string[] ArrayField; + public string[] ArrayProperty { get; set; } + public string[,] ArrayField2; + public string[,] ArrayProperty2 { get; set; } + } + + void Test(int i) + { + // Collection initializer + var dict = new Dictionary() { [0] = "Zero", [1] = "One", [i + 2] = "Two" }; + + // Indexed initializer + var compound = new Compound() + { + DictionaryField = { [0] = "Zero", [1] = "One", [i + 2] = "Two" }, + DictionaryProperty = { [3] = "Three", [2] = "Two", [i + 1] = "One" }, + ArrayField = { [0] = "Zero", [i + 1] = "One" }, + ArrayField2 = { [0, 1] = "i", [1, i + 0] = "1" }, + ArrayProperty = { [1] = "One", [i + 2] = "Two" }, + ArrayProperty2 = { [0, 1] = "i", [1, i + 0] = "1" }, + }; + } +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 256f8d8ad36..2f83bbd696e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -495,6 +495,7 @@ | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | semmle.label | successor | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | semmle.label | successor | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | semmle.label | successor | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | semmle.label | successor | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | semmle.label | null | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | semmle.label | non-null | @@ -554,12 +555,28 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | semmle.label | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | semmle.label | successor | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | semmle.label | successor | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | semmle.label | successor | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | semmle.label | successor | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | semmle.label | non-null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | semmle.label | successor | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | successor | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | semmle.label | successor | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | semmle.label | successor | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | semmle.label | successor | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | semmle.label | successor | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | semmle.label | successor | @@ -1892,93 +1909,196 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | semmle.label | successor | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | semmle.label | successor | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | semmle.label | successor | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | semmle.label | successor | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | semmle.label | successor | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | semmle.label | successor | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | semmle.label | successor | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | semmle.label | successor | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:20:6:22 | {...} | semmle.label | successor | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:28:8:30 | {...} | semmle.label | successor | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | semmle.label | successor | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | semmle.label | successor | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | semmle.label | successor | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | semmle.label | successor | -| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | semmle.label | successor | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | semmle.label | successor | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:11:5:14:5 | {...} | semmle.label | successor | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:12:9:12:54 | ... ...; | semmle.label | successor | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:34:12:35 | "" | semmle.label | successor | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:13:9:13:64 | ... ...; | semmle.label | successor | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:44:12:44 | 0 | semmle.label | successor | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:17:12:53 | object creation of type Initializers | semmle.label | successor | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:13:12:53 | Initializers i = ... | semmle.label | successor | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:51:12:51 | 1 | semmle.label | successor | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:40:12:44 | ... = ... | semmle.label | successor | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:47:12:51 | ... = ... | semmle.label | successor | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:38:12:53 | { ..., ... } | semmle.label | successor | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:47:12:47 | access to property G | semmle.label | successor | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | semmle.label | successor | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | exit M | semmle.label | successor | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:39:13:39 | access to local variable i | semmle.label | successor | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | semmle.label | successor | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:59:13:60 | "" | semmle.label | successor | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:37:13:63 | { ..., ... } | semmle.label | successor | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:42:13:61 | object creation of type Initializers | semmle.label | successor | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | semmle.label | successor | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:23:20:23 | this access | semmle.label | successor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | semmle.label | successor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | semmle.label | successor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | semmle.label | successor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | semmle.label | successor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | semmle.label | successor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | semmle.label | successor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | semmle.label | successor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | semmle.label | successor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor | semmle.label | successor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:26:13:26:13 | this access | semmle.label | successor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | semmle.label | successor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | semmle.label | successor | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | semmle.label | successor | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | semmle.label | successor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:24:29:33 | {...} | semmle.label | successor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:27:33:40 | {...} | semmle.label | successor | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | semmle.label | successor | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | semmle.label | successor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | semmle.label | successor | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:26:13:26:13 | this access | semmle.label | successor | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:31 | ...; | semmle.label | successor | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:30:29:30 | 3 | semmle.label | successor | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | exit Sub | semmle.label | successor | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:26 | this access | semmle.label | successor | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:30 | ... = ... | semmle.label | successor | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | semmle.label | successor | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:29:31:38 | {...} | semmle.label | successor | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:36 | ...; | semmle.label | successor | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:35:31:35 | access to parameter i | semmle.label | successor | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | semmle.label | successor | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:31 | this access | semmle.label | successor | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:35 | ... = ... | semmle.label | successor | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:20:23:20:23 | this access | semmle.label | successor | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:38 | ...; | semmle.label | successor | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:33:33:33 | access to parameter i | semmle.label | successor | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | semmle.label | successor | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:29 | this access | semmle.label | successor | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j | semmle.label | successor | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... | semmle.label | successor | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... | semmle.label | successor | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | semmle.label | successor | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | semmle.label | successor | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | semmle.label | successor | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | semmle.label | successor | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | semmle.label | successor | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | semmle.label | successor | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | semmle.label | successor | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | semmle.label | successor | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | semmle.label | successor | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | semmle.label | successor | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | semmle.label | successor | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:20:8:22 | {...} | semmle.label | successor | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:28:10:30 | {...} | semmle.label | successor | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | semmle.label | successor | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | semmle.label | successor | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | semmle.label | successor | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | semmle.label | successor | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | semmle.label | successor | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | semmle.label | successor | +| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | semmle.label | successor | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | semmle.label | successor | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | semmle.label | successor | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | exit Initializers | semmle.label | successor | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:13:5:16:5 | {...} | semmle.label | successor | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:14:9:14:54 | ... ...; | semmle.label | successor | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:34:14:35 | "" | semmle.label | successor | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:15:9:15:64 | ... ...; | semmle.label | successor | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:44:14:44 | 0 | semmle.label | successor | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:17:14:53 | object creation of type Initializers | semmle.label | successor | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:13:14:53 | Initializers i = ... | semmle.label | successor | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:51:14:51 | 1 | semmle.label | successor | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:40:14:44 | ... = ... | semmle.label | successor | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | semmle.label | successor | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | semmle.label | successor | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | semmle.label | successor | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | semmle.label | successor | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | semmle.label | successor | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | semmle.label | successor | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | semmle.label | successor | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | semmle.label | successor | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:37:15:63 | { ..., ... } | semmle.label | successor | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:42:15:61 | object creation of type Initializers | semmle.label | successor | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | semmle.label | successor | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:22:23:22:23 | this access | semmle.label | successor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | semmle.label | successor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | semmle.label | successor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | semmle.label | successor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | semmle.label | successor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | semmle.label | successor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | semmle.label | successor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | semmle.label | successor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | semmle.label | successor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | exit NoConstructor | semmle.label | successor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:28:13:28:13 | this access | semmle.label | successor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | semmle.label | successor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | semmle.label | successor | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | semmle.label | successor | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | semmle.label | successor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:24:31:33 | {...} | semmle.label | successor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:27:35:40 | {...} | semmle.label | successor | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | semmle.label | successor | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | semmle.label | successor | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | semmle.label | successor | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:28:13:28:13 | this access | semmle.label | successor | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:31 | ...; | semmle.label | successor | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:30:31:30 | 3 | semmle.label | successor | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | semmle.label | successor | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:26 | this access | semmle.label | successor | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:30 | ... = ... | semmle.label | successor | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | semmle.label | successor | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:29:33:38 | {...} | semmle.label | successor | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:36 | ...; | semmle.label | successor | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:35:33:35 | access to parameter i | semmle.label | successor | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | semmle.label | successor | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:31 | this access | semmle.label | successor | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:35 | ... = ... | semmle.label | successor | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:22:23:22:23 | this access | semmle.label | successor | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:38 | ...; | semmle.label | successor | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:33:35:33 | access to parameter i | semmle.label | successor | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | exit Sub | semmle.label | successor | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:29 | this access | semmle.label | successor | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:37:35:37 | access to parameter j | semmle.label | successor | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:29:35:37 | ... = ... | semmle.label | successor | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:37 | ... + ... | semmle.label | successor | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:52:5:66:5 | {...} | semmle.label | successor | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | semmle.label | successor | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | semmle.label | successor | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | semmle.label | successor | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:53:54:53 | 0 | semmle.label | successor | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | semmle.label | successor | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | semmle.label | successor | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:67:54:67 | 1 | semmle.label | successor | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:58:54:63 | "Zero" | semmle.label | successor | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | semmle.label | successor | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | semmle.label | successor | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | semmle.label | successor | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:72:54:76 | "One" | semmle.label | successor | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | semmle.label | successor | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | semmle.label | successor | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | semmle.label | successor | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:84:54:84 | 2 | semmle.label | successor | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:89:54:93 | "Two" | semmle.label | successor | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:84 | ... + ... | semmle.label | successor | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | semmle.label | successor | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | semmle.label | successor | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | semmle.label | successor | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:34:59:34 | 0 | semmle.label | successor | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | semmle.label | successor | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:37:60:37 | 3 | semmle.label | successor | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | semmle.label | successor | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | semmle.label | successor | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:48:59:48 | 1 | semmle.label | successor | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:39:59:44 | "Zero" | semmle.label | successor | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | semmle.label | successor | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | semmle.label | successor | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | semmle.label | successor | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:53:59:57 | "One" | semmle.label | successor | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | semmle.label | successor | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | semmle.label | successor | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | semmle.label | successor | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:65:59:65 | 2 | semmle.label | successor | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:70:59:74 | "Two" | semmle.label | successor | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:65 | ... + ... | semmle.label | successor | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | semmle.label | successor | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | semmle.label | successor | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:29:61:29 | 0 | semmle.label | successor | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | semmle.label | successor | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | semmle.label | successor | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:52:60:52 | 2 | semmle.label | successor | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:42:60:48 | "Three" | semmle.label | successor | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | semmle.label | successor | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | semmle.label | successor | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | semmle.label | successor | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:57:60:61 | "Two" | semmle.label | successor | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | semmle.label | successor | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | semmle.label | successor | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | semmle.label | successor | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:69:60:69 | 1 | semmle.label | successor | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:74:60:78 | "One" | semmle.label | successor | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:69 | ... + ... | semmle.label | successor | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | semmle.label | successor | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:30:62:30 | 0 | semmle.label | successor | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | semmle.label | successor | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | semmle.label | successor | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:34:61:39 | "Zero" | semmle.label | successor | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | semmle.label | successor | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | semmle.label | successor | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:47:61:47 | 1 | semmle.label | successor | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:52:61:56 | "One" | semmle.label | successor | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:47 | ... + ... | semmle.label | successor | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | semmle.label | successor | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | semmle.label | successor | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | semmle.label | successor | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:44:62:44 | 1 | semmle.label | successor | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:33:62:33 | 1 | semmle.label | successor | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:38:62:40 | "i" | semmle.label | successor | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | semmle.label | successor | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:47:62:47 | access to parameter i | semmle.label | successor | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:51:62:51 | 0 | semmle.label | successor | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:56:62:58 | "1" | semmle.label | successor | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:51 | ... + ... | semmle.label | successor | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | semmle.label | successor | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | semmle.label | successor | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:33:64:33 | 0 | semmle.label | successor | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | semmle.label | successor | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | semmle.label | successor | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:37:63:41 | "One" | semmle.label | successor | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | semmle.label | successor | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:49:63:49 | 2 | semmle.label | successor | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:54:63:58 | "Two" | semmle.label | successor | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:49 | ... + ... | semmle.label | successor | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | semmle.label | successor | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | semmle.label | successor | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | semmle.label | successor | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | semmle.label | successor | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:47:64:47 | 1 | semmle.label | successor | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:36:64:36 | 1 | semmle.label | successor | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:41:64:43 | "i" | semmle.label | successor | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | semmle.label | successor | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | semmle.label | successor | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:50:64:50 | access to parameter i | semmle.label | successor | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:54:64:54 | 0 | semmle.label | successor | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:59:64:61 | "1" | semmle.label | successor | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:54 | ... + ... | semmle.label | successor | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | semmle.label | successor | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | semmle.label | successor | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | semmle.label | successor | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index 2974031c5db..cb591a74ce8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -656,6 +656,7 @@ entryPoint | CompileTimeOperators.cs:15:10:15:15 | Typeof | CompileTimeOperators.cs:16:5:18:5 | {...} | | CompileTimeOperators.cs:20:12:20:17 | Nameof | CompileTimeOperators.cs:21:5:23:5 | {...} | | CompileTimeOperators.cs:28:10:28:10 | M | CompileTimeOperators.cs:29:5:41:5 | {...} | +| ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:5:10:5:11 | M2 | ConditionalAccess.cs:5:26:5:26 | access to parameter s | | ConditionalAccess.cs:7:10:7:11 | M3 | ConditionalAccess.cs:7:39:7:46 | ... ?? ... | @@ -663,7 +664,9 @@ entryPoint | ConditionalAccess.cs:11:9:11:10 | M5 | ConditionalAccess.cs:12:5:17:5 | {...} | | ConditionalAccess.cs:19:12:19:13 | M6 | ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | | ConditionalAccess.cs:21:10:21:11 | M7 | ConditionalAccess.cs:22:5:26:5 | {...} | -| ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | +| ConditionalAccess.cs:30:10:30:12 | Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:32:10:32:11 | M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | | Conditions.cs:3:10:3:19 | IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:11:9:11:10 | M1 | Conditions.cs:12:5:20:5 | {...} | | Conditions.cs:22:9:22:10 | M2 | Conditions.cs:23:5:31:5 | {...} | @@ -717,13 +720,14 @@ entryPoint | Foreach.cs:24:10:24:11 | M4 | Foreach.cs:25:5:28:5 | {...} | | Foreach.cs:30:10:30:11 | M5 | Foreach.cs:31:5:34:5 | {...} | | Foreach.cs:36:10:36:11 | M6 | Foreach.cs:37:5:40:5 | {...} | -| Initializers.cs:6:5:6:16 | Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:8:5:8:16 | Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:10:10:10:10 | M | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:18:11:18:23 | NoConstructor | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:29:9:29:11 | Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:31:9:31:11 | Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:33:9:33:11 | Sub | Initializers.cs:20:23:20:23 | this access | +| Initializers.cs:8:5:8:16 | Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:10:5:10:16 | Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:12:10:12:10 | M | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:20:11:20:23 | NoConstructor | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:31:9:31:11 | Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:33:9:33:11 | Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:35:9:35:11 | Sub | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:51:10:51:13 | Test | Initializers.cs:52:5:66:5 | {...} | | LoopUnrolling.cs:7:10:7:11 | M1 | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:15:10:15:11 | M2 | LoopUnrolling.cs:16:5:20:5 | {...} | | LoopUnrolling.cs:22:10:22:11 | M3 | LoopUnrolling.cs:23:5:27:5 | {...} | diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected new file mode 100644 index 00000000000..739bb6c7a03 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected @@ -0,0 +1,87 @@ +assignedMembers +| csharp6.cs:12:16:12:20 | Value | csharp6.cs:15:9:15:10 | 20 | +| csharp6.cs:57:40:57:54 | DictionaryField | csharp6.cs:73:31:73:72 | { ..., ... } | +| csharp6.cs:58:40:58:57 | DictionaryProperty | csharp6.cs:74:34:74:76 | { ..., ... } | +| csharp6.cs:59:25:59:34 | ArrayField | csharp6.cs:75:26:75:54 | { ..., ... } | +| csharp6.cs:60:25:60:37 | ArrayProperty | csharp6.cs:77:29:77:56 | { ..., ... } | +| csharp6.cs:61:26:61:36 | ArrayField2 | csharp6.cs:76:27:76:56 | { ..., ... } | +| csharp6.cs:62:26:62:39 | ArrayProperty2 | csharp6.cs:78:30:78:59 | { ..., ... } | +indexerCalls +| csharp6.cs:32:68:32:70 | access to indexer | 0 | csharp6.cs:32:69:32:69 | 2 | +| csharp6.cs:32:68:32:73 | access to indexer | 0 | csharp6.cs:32:72:32:72 | 1 | +| csharp6.cs:68:52:68:54 | access to indexer | 0 | csharp6.cs:68:53:68:53 | 0 | +| csharp6.cs:68:52:68:54 | access to indexer | 1 | csharp6.cs:68:58:68:63 | "Zero" | +| csharp6.cs:68:66:68:68 | access to indexer | 0 | csharp6.cs:68:67:68:67 | 1 | +| csharp6.cs:68:66:68:68 | access to indexer | 1 | csharp6.cs:68:72:68:76 | "One" | +| csharp6.cs:68:79:68:81 | access to indexer | 0 | csharp6.cs:68:80:68:80 | 2 | +| csharp6.cs:68:79:68:81 | access to indexer | 1 | csharp6.cs:68:85:68:89 | "Two" | +| csharp6.cs:73:33:73:35 | access to indexer | 0 | csharp6.cs:73:34:73:34 | 0 | +| csharp6.cs:73:33:73:35 | access to indexer | 1 | csharp6.cs:73:39:73:44 | "Zero" | +| csharp6.cs:73:47:73:49 | access to indexer | 0 | csharp6.cs:73:48:73:48 | 1 | +| csharp6.cs:73:47:73:49 | access to indexer | 1 | csharp6.cs:73:53:73:57 | "One" | +| csharp6.cs:73:60:73:62 | access to indexer | 0 | csharp6.cs:73:61:73:61 | 2 | +| csharp6.cs:73:60:73:62 | access to indexer | 1 | csharp6.cs:73:66:73:70 | "Two" | +| csharp6.cs:74:36:74:38 | access to indexer | 0 | csharp6.cs:74:37:74:37 | 3 | +| csharp6.cs:74:36:74:38 | access to indexer | 1 | csharp6.cs:74:42:74:48 | "Three" | +| csharp6.cs:74:51:74:53 | access to indexer | 0 | csharp6.cs:74:52:74:52 | 2 | +| csharp6.cs:74:51:74:53 | access to indexer | 1 | csharp6.cs:74:57:74:61 | "Two" | +| csharp6.cs:74:64:74:66 | access to indexer | 0 | csharp6.cs:74:65:74:65 | 1 | +| csharp6.cs:74:64:74:66 | access to indexer | 1 | csharp6.cs:74:70:74:74 | "One" | +elementAssignments +| csharp6.cs:68:52:68:54 | access to indexer | csharp6.cs:68:52:68:63 | ... = ... | 0 | csharp6.cs:68:53:68:53 | 0 | +| csharp6.cs:68:66:68:68 | access to indexer | csharp6.cs:68:66:68:76 | ... = ... | 0 | csharp6.cs:68:67:68:67 | 1 | +| csharp6.cs:68:79:68:81 | access to indexer | csharp6.cs:68:79:68:89 | ... = ... | 0 | csharp6.cs:68:80:68:80 | 2 | +| csharp6.cs:73:33:73:35 | access to indexer | csharp6.cs:73:33:73:44 | ... = ... | 0 | csharp6.cs:73:34:73:34 | 0 | +| csharp6.cs:73:47:73:49 | access to indexer | csharp6.cs:73:47:73:57 | ... = ... | 0 | csharp6.cs:73:48:73:48 | 1 | +| csharp6.cs:73:60:73:62 | access to indexer | csharp6.cs:73:60:73:70 | ... = ... | 0 | csharp6.cs:73:61:73:61 | 2 | +| csharp6.cs:74:36:74:38 | access to indexer | csharp6.cs:74:36:74:48 | ... = ... | 0 | csharp6.cs:74:37:74:37 | 3 | +| csharp6.cs:74:51:74:53 | access to indexer | csharp6.cs:74:51:74:61 | ... = ... | 0 | csharp6.cs:74:52:74:52 | 2 | +| csharp6.cs:74:64:74:66 | access to indexer | csharp6.cs:74:64:74:74 | ... = ... | 0 | csharp6.cs:74:65:74:65 | 1 | +| csharp6.cs:75:28:75:30 | access to array element | csharp6.cs:75:28:75:39 | ... = ... | 0 | csharp6.cs:75:29:75:29 | 0 | +| csharp6.cs:75:42:75:44 | access to array element | csharp6.cs:75:42:75:52 | ... = ... | 0 | csharp6.cs:75:43:75:43 | 1 | +| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 0 | csharp6.cs:76:30:76:30 | 0 | +| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 1 | csharp6.cs:76:33:76:33 | 1 | +| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 0 | csharp6.cs:76:44:76:44 | 1 | +| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 1 | csharp6.cs:76:47:76:47 | 0 | +| csharp6.cs:77:31:77:33 | access to array element | csharp6.cs:77:31:77:41 | ... = ... | 0 | csharp6.cs:77:32:77:32 | 1 | +| csharp6.cs:77:44:77:46 | access to array element | csharp6.cs:77:44:77:54 | ... = ... | 0 | csharp6.cs:77:45:77:45 | 2 | +| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 0 | csharp6.cs:78:33:78:33 | 0 | +| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 1 | csharp6.cs:78:36:78:36 | 1 | +| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 0 | csharp6.cs:78:47:78:47 | 1 | +| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 1 | csharp6.cs:78:50:78:50 | 0 | +arrayQualifiers +| csharp6.cs:32:68:32:70 | access to indexer | csharp6.cs:32:38:32:66 | object creation of type Dictionary | +| csharp6.cs:32:68:32:73 | access to indexer | csharp6.cs:32:68:32:70 | access to indexer | +initializers +| csharp6.cs:68:50:68:91 | { ..., ... } | 0 | csharp6.cs:68:52:68:63 | ... = ... | +| csharp6.cs:68:50:68:91 | { ..., ... } | 1 | csharp6.cs:68:66:68:76 | ... = ... | +| csharp6.cs:68:50:68:91 | { ..., ... } | 2 | csharp6.cs:68:79:68:89 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 0 | csharp6.cs:73:13:73:72 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 1 | csharp6.cs:74:13:74:76 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 2 | csharp6.cs:75:13:75:54 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 3 | csharp6.cs:76:13:76:56 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 4 | csharp6.cs:77:13:77:56 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 5 | csharp6.cs:78:13:78:59 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 0 | csharp6.cs:73:33:73:44 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 1 | csharp6.cs:73:47:73:57 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 2 | csharp6.cs:73:60:73:70 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 0 | csharp6.cs:74:36:74:48 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 1 | csharp6.cs:74:51:74:61 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 2 | csharp6.cs:74:64:74:74 | ... = ... | +| csharp6.cs:75:26:75:54 | { ..., ... } | 0 | csharp6.cs:75:28:75:39 | ... = ... | +| csharp6.cs:75:26:75:54 | { ..., ... } | 1 | csharp6.cs:75:42:75:52 | ... = ... | +| csharp6.cs:76:27:76:56 | { ..., ... } | 0 | csharp6.cs:76:29:76:40 | ... = ... | +| csharp6.cs:76:27:76:56 | { ..., ... } | 1 | csharp6.cs:76:43:76:54 | ... = ... | +| csharp6.cs:77:29:77:56 | { ..., ... } | 0 | csharp6.cs:77:31:77:41 | ... = ... | +| csharp6.cs:77:29:77:56 | { ..., ... } | 1 | csharp6.cs:77:44:77:54 | ... = ... | +| csharp6.cs:78:30:78:59 | { ..., ... } | 0 | csharp6.cs:78:32:78:43 | ... = ... | +| csharp6.cs:78:30:78:59 | { ..., ... } | 1 | csharp6.cs:78:46:78:57 | ... = ... | +initializerType +| csharp6.cs:68:50:68:91 | { ..., ... } | Dictionary | +| csharp6.cs:72:9:79:9 | { ..., ... } | Compound | +| csharp6.cs:73:31:73:72 | { ..., ... } | Dictionary | +| csharp6.cs:74:34:74:76 | { ..., ... } | Dictionary | +| csharp6.cs:75:26:75:54 | { ..., ... } | String[] | +| csharp6.cs:76:27:76:56 | { ..., ... } | String[,] | +| csharp6.cs:77:29:77:56 | { ..., ... } | String[] | +| csharp6.cs:78:30:78:59 | { ..., ... } | String[,] | diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql new file mode 100644 index 00000000000..f3ef63fe225 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql @@ -0,0 +1,28 @@ +import csharp + +query predicate assignedMembers(AssignableMember member, Expr value) { + member.fromSource() and + value = member.getAnAssignedValue() +} + +query predicate indexerCalls(IndexerCall indexer, int arg, Expr value) { + value = indexer.getArgument(arg) +} + +query predicate elementAssignments( + ElementWrite write, Assignment assignment, int index, Expr indexer +) { + write = assignment.getLValue() and indexer = write.getIndex(index) +} + +query predicate arrayQualifiers(ElementAccess access, Expr qualifier) { + qualifier = access.getQualifier() +} + +query predicate initializers(ObjectInitializer init, int item, Expr expr) { + expr = init.getMemberInitializer(item) +} + +query predicate initializerType(ObjectInitializer init, string type) { + type = init.getType().toStringWithTypes() +} diff --git a/csharp/ql/test/library-tests/csharp6/csharp6.cs b/csharp/ql/test/library-tests/csharp6/csharp6.cs index 856c2e7e549..ec349106e95 100644 --- a/csharp/ql/test/library-tests/csharp6/csharp6.cs +++ b/csharp/ql/test/library-tests/csharp6/csharp6.cs @@ -50,4 +50,34 @@ class TestCSharp6 int this[int i] => i; } -// semmle-extractor-options: /r:System.Linq.dll +class IndexInitializers +{ + class Compound + { + public Dictionary DictionaryField; + public Dictionary DictionaryProperty { get; set; } + public string[] ArrayField; + public string[] ArrayProperty { get; set; } + public string[,] ArrayField2; + public string[,] ArrayProperty2 { get; set; } + } + + void Test() + { + // Collection initializer + var dict = new Dictionary() { [0] = "Zero", [1] = "One", [2] = "Two" }; + + // Indexed initializer + var compound = new Compound() + { + DictionaryField = { [0] = "Zero", [1] = "One", [2] = "Two" }, + DictionaryProperty = { [3] = "Three", [2] = "Two", [1] = "One" }, + ArrayField = { [0] = "Zero", [1] = "One" }, + ArrayField2 = { [0, 1] = "i", [1, 0] = "1" }, + ArrayProperty = { [1] = "One", [2] = "Two" }, + ArrayProperty2 = { [0, 1] = "i", [1, 0] = "1" }, + }; + } +} + +// semmle-extractor-options: /r:System.Linq.dll /langerversion:6.0 diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index cad303fa914..10c661579f1 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -231,16 +231,10 @@ | CSharp7.cs:283:13:283:48 | SSA def(dict) | CSharp7.cs:284:20:284:23 | access to local variable dict | | CSharp7.cs:283:20:283:48 | object creation of type Dictionary | CSharp7.cs:283:13:283:48 | SSA def(dict) | | CSharp7.cs:284:13:284:62 | SSA def(list) | CSharp7.cs:286:39:286:42 | access to local variable list | -| CSharp7.cs:284:20:284:23 | access to local variable dict | CSharp7.cs:284:20:284:62 | [library code] call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:20:284:62 | call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:32:284:61 | [implicit argument 0] (...) => ... | | CSharp7.cs:284:20:284:62 | call to method Select | CSharp7.cs:284:13:284:62 | SSA def(list) | | CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:41:284:44 | access to parameter item | -| CSharp7.cs:284:32:284:61 | [output] (...) => ... | CSharp7.cs:284:20:284:62 | [library code] call to method Select | | CSharp7.cs:284:41:284:44 | access to parameter item | CSharp7.cs:284:51:284:54 | access to parameter item | | CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | [library code] access to property Value | -| CSharp7.cs:284:51:284:60 | [library code] access to property Value | CSharp7.cs:284:51:284:60 | access to property Value | | CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs index db4cd4b643d..948d0498983 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs @@ -161,9 +161,14 @@ public class A2 { } - public void M() + public virtual void M(object o) { + Sink(o); + } + public static void CallM(A2 a2, object o) + { + a2.M(o); } public void Callsite(InterfaceB intF) @@ -172,28 +177,31 @@ public class A2 // in both possible implementations of foo, this callsite is relevant // in IntA, it improves virtual dispatch, // and in IntB, it improves the dataflow analysis. - intF.Foo(b, new object(), false); + intF.Foo(b, new object(), false); // no flow to `Sink()` via `A2.M()`, but flow via `IntA.Foo()` + + CallM(b, new object()); // no flow to `Sink()` + CallM(this, new object()); // flow to `Sink()` } - private class B : A2 + public class B : A2 { - public void M() + public override void M(object o) { } } - private class IntA : InterfaceB + public class IntA : InterfaceB { public void Foo(A2 obj, object o, bool cond) { - obj.M(); + obj.M(o); Sink(o); } } - private class IntB : InterfaceB + public class IntB : InterfaceB { public void Foo(A2 obj, object o, bool cond) diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected index 0a39a463c57..c17fa754c4f 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected @@ -26,8 +26,12 @@ edges | CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | | CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:189:40:189:40 | o : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:197:40:197:40 | o : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:169:44:169:44 | o : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | nodes | CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o | @@ -66,9 +70,14 @@ nodes | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object | -| CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | semmle.label | access to parameter o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | semmle.label | access to parameter o | #select | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o | @@ -87,4 +96,5 @@ nodes | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | $@ | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 3565ba0b6ea..5f1bf2a6731 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -7,6 +7,8 @@ public class CollectionFlow { public class A { } + public A[] As; + public void ArrayInitializerFlow() { var a = new A(); @@ -25,6 +27,24 @@ public class CollectionFlow Sink(First(@as)); // no flow } + public void ArrayInitializerCSharp6Flow() + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = a } }; + Sink(c.As[0]); // flow + SinkElem(c.As); // flow + Sink(First(c.As)); // flow + } + + public void ArrayInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = other } }; + Sink(c.As[0]); // no flow + SinkElem(c.As); // no flow + Sink(First(c.As)); // no flow + } + public void ArrayAssignmentFlow() { var a = new A(); @@ -108,7 +128,7 @@ public class CollectionFlow Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -130,7 +150,7 @@ public class CollectionFlow Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -144,14 +164,36 @@ public class CollectionFlow Sink(DictValuesFirst(dict)); // no flow } + public void DictionaryValueInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary() { [0] = a }; + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow + Sink(DictValuesFirst(dict)); // flow + } + + public void DictionaryValueInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var dict = new Dictionary() { [0] = other }; + Sink(dict[0]); // no flow + SinkDictValue(dict); // no flow + Sink(DictIndexZero(dict)); // no flow + Sink(DictFirstValue(dict)); // no flow + Sink(DictValuesFirst(dict)); // no flow + } + public void DictionaryKeyInitializerFlow() { var a = new A(); var dict = new Dictionary() { { a, 0 } }; - Sink(dict.Keys.First()); // flow [MISSING] - SinkDictKey(dict); // flow [MISSING] - Sink(DictKeysFirst(dict)); // flow [MISSING] - Sink(DictFirstKey(dict)); // flow [MISSING] + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow } public void DictionaryKeyInitializerNoFlow(A other) @@ -163,6 +205,25 @@ public class CollectionFlow Sink(DictFirstKey(dict)); // no flow } + public void DictionaryKeyInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary() { [a] = 0 }; + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow + } + + public void DictionaryKeyInitializerCSharp6NoFlow(A other) + { + var dict = new Dictionary() { [other] = 0 }; + Sink(dict.Keys.First()); // no flow + SinkDictKey(dict); // no flow + Sink(DictKeysFirst(dict)); // no flow + Sink(DictFirstKey(dict)); // no flow + } + public void ForeachFlow() { var a = new A(); @@ -202,7 +263,110 @@ public class CollectionFlow list.Add(a); var enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) - Sink(enumerator.Current); // flow [MISSING] + Sink(enumerator.Current); // flow + } + + public void ListGetEnumeratorNoFlow(A other) + { + var list = new List(); + list.Add(other); + var enumerator = list.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // no flow + } + + public void SelectFlow() + { + var a = new A(); + var list = new List>(); + list.Add(new KeyValuePair(a, 0)); + list.Select(kvp => + { + Sink(kvp.Key); // flow + return kvp.Value; + }); + } + + public void SelectNoFlow() + { + var a = new A(); + var list = new List>(); + list.Add(new KeyValuePair(a, 0)); + list.Select(kvp => + { + Sink(kvp.Value); // no flow + return kvp.Value; + }); + } + + void SetArray(A[] array, A element) => array[0] = element; + + public void ArraySetterFlow() + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, a); + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void ArraySetterNoFlow(A other) + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, other); + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + void SetList(List list, A element) => list.Add(element); + + public void ListSetterFlow() + { + var a = new A(); + var list = new List(); + SetList(list, a); + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListSetterNoFlow(A other) + { + var list = new List(); + SetList(list, other); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void ParamsFlow() + { + SinkParams(new A()); // flow + SinkParams(null, new A()); // flow + SinkParams(null, new A(), null); // flow + SinkParams(new A[] { new A() }); // flow + } + + public void ParamsNoFlow(A other) + { + SinkParams(other); // no flow + SinkParams(null, other); // no flow + SinkParams(null, other, null); // no flow + SinkParams(new A[] { other }); // no flow + } + + public void ListAddClearNoFlow() + { + var a = new A(); + var list = new List(); + list.Add(a); + list.Clear(); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow } public static void Sink(T t) { } @@ -228,4 +392,6 @@ public class CollectionFlow public static T DictKeysFirst(IDictionary dict) => dict.Keys.First(); public static T DictFirstKey(IDictionary dict) => dict.First().Key; + + public static void SinkParams(params T[] args) => Sink(args[0]); } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index c6cc298ea94..63b053f20f7 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,235 +1,399 @@ edges -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | CollectionFlow.cs:16:14:16:23 | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | CollectionFlow.cs:35:14:35:23 | call to method First | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:63:22:63:25 | access to local variable list : List | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:24:64:27 | access to local variable list : List | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:80:22:80:25 | access to local variable list : List | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:24:81:27 | access to local variable list : List | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:99:22:99:25 | access to local variable list : List | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:24:100:27 | access to local variable list : List | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | CollectionFlow.cs:210:52:210:56 | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List | CollectionFlow.cs:212:63:212:69 | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:15:27:15:27 | access to local variable a : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | CollectionFlow.cs:16:14:16:19 | access to array element | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | CollectionFlow.cs:18:14:18:23 | call to method First | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:33:53:33:53 | access to local variable a : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | +| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] | CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | +| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | CollectionFlow.cs:34:14:34:20 | access to array element | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] | CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | +| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] | CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | +| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | CollectionFlow.cs:36:14:36:24 | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:52:18:52:18 | access to local variable a : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:19 | access to array element | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | CollectionFlow.cs:55:14:55:23 | call to method First | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:72:19:72:19 | access to local variable a : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:20 | access to indexer | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | CollectionFlow.cs:91:14:91:20 | access to indexer | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:108:18:108:18 | access to local variable a : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:20 | access to indexer | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | CollectionFlow.cs:171:14:171:20 | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | CollectionFlow.cs:193:14:193:30 | call to method First | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | CollectionFlow.cs:212:14:212:30 | call to method First | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:230:27:230:27 | access to local variable a : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | +| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:245:27:245:27 | access to local variable a : A | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | +| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:248:18:248:35 | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:263:18:263:18 | access to local variable a : A | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | +| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:266:18:266:35 | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:282:43:282:43 | access to local variable a : A | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] | CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] | CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | +| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | CollectionFlow.cs:285:18:285:24 | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:308:23:308:23 | access to local variable a : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:19 | access to array element | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | CollectionFlow.cs:311:14:311:23 | call to method First | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:330:23:330:23 | access to local variable a : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:20 | access to indexer | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict [[], Value] | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | CollectionFlow.cs:378:75:378:81 | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] | CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | CollectionFlow.cs:380:73:380:89 | call to method First | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | nodes -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:14:14:14:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:16:14:16:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:33:14:33:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:35:14:35:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:16:14:16:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:18:14:18:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | semmle.label | { ..., ... } [As, []] | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:34:14:34:20 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:36:14:36:24 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:53:14:53:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:55:14:55:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:62:14:62:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:64:14:64:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:71:14:71:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:73:14:73:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:79:14:79:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:81:14:81:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:89:14:89:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:91:14:91:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:98:14:98:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:100:14:100:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:119:14:119:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:130:14:130:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:140:14:140:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:171:18:171:18 | access to local variable x | semmle.label | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:187:18:187:35 | access to property Current | semmle.label | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | semmle.label | ts : A[] | -| CollectionFlow.cs:210:52:210:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List | semmle.label | list : List | -| CollectionFlow.cs:212:63:212:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | semmle.label | dict : Dictionary | -| CollectionFlow.cs:214:75:214:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:53:14:53:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:55:14:55:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:73:14:73:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:75:14:75:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:91:14:91:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:93:14:93:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:109:14:109:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:111:14:111:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | semmle.label | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:193:14:193:30 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:212:14:212:30 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | semmle.label | SSA def(x) : A | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:232:18:232:18 | access to local variable x | semmle.label | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:248:18:248:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:266:18:266:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] | semmle.label | [post] access to local variable list [[], Key] | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | semmle.label | object creation of type KeyValuePair [Key] : A | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] | semmle.label | access to local variable list [[], Key] | +| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | semmle.label | kvp [Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | semmle.label | access to parameter kvp [Key] : A | +| CollectionFlow.cs:285:18:285:24 | access to property Key | semmle.label | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:309:14:309:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:311:14:311:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:331:14:331:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:333:14:333:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | semmle.label | array creation of type A[] [[]] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict [[], Value] | semmle.label | dict [[], Value] | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | semmle.label | access to parameter dict [[], Value] | +| CollectionFlow.cs:378:75:378:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] | semmle.label | dict [[], Key] | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | semmle.label | access to parameter dict [[], Key] | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:380:73:380:89 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:69 | access to array element | semmle.label | access to array element | #select -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | $@ | CollectionFlow.cs:14:14:14:19 | access to array element | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:23 | call to method First | $@ | CollectionFlow.cs:16:14:16:23 | call to method First | call to method First | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | $@ | CollectionFlow.cs:33:14:33:19 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:14:35:23 | call to method First | $@ | CollectionFlow.cs:35:14:35:23 | call to method First | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | $@ | CollectionFlow.cs:62:14:62:20 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | $@ | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | $@ | CollectionFlow.cs:79:14:79:20 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | $@ | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | $@ | CollectionFlow.cs:98:14:98:20 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | $@ | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | $@ | CollectionFlow.cs:119:14:119:20 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | $@ | CollectionFlow.cs:140:14:140:20 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | $@ | CollectionFlow.cs:171:18:171:18 | access to local variable x | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | $@ | CollectionFlow.cs:187:18:187:35 | access to property Current | access to property Current | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | $@ | CollectionFlow.cs:16:14:16:19 | access to array element | access to array element | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:18:14:18:23 | call to method First | $@ | CollectionFlow.cs:18:14:18:23 | call to method First | call to method First | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:34:14:34:20 | access to array element | $@ | CollectionFlow.cs:34:14:34:20 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:36:14:36:24 | call to method First | $@ | CollectionFlow.cs:36:14:36:24 | call to method First | call to method First | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | $@ | CollectionFlow.cs:53:14:53:19 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:23 | call to method First | $@ | CollectionFlow.cs:55:14:55:23 | call to method First | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:193:14:193:30 | call to method First | $@ | CollectionFlow.cs:193:14:193:30 | call to method First | call to method First | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:212:14:212:30 | call to method First | $@ | CollectionFlow.cs:212:14:212:30 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | $@ | CollectionFlow.cs:232:18:232:18 | access to local variable x | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | $@ | CollectionFlow.cs:248:18:248:35 | access to property Current | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:266:18:266:35 | access to property Current | $@ | CollectionFlow.cs:266:18:266:35 | access to property Current | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:285:18:285:24 | access to property Key | $@ | CollectionFlow.cs:285:18:285:24 | access to property Key | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:309:14:309:19 | access to array element | $@ | CollectionFlow.cs:309:14:309:19 | access to array element | access to array element | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:311:14:311:23 | call to method First | $@ | CollectionFlow.cs:311:14:311:23 | call to method First | call to method First | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql index d1290562252..7c2c322f47f 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql @@ -5,7 +5,7 @@ import csharp import DataFlow::PathGraph -class Conf extends TaintTracking::Configuration { +class Conf extends DataFlow::Configuration { Conf() { this = "ArrayFlowConf" } override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation } diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index 3d0a0a83ed5..ff675293cf7 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -124,18 +124,18 @@ edges | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:11:24:11:24 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:15:26:15:26 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:19:32:19:32 | access to local variable o : Object | +| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:23:32:23:32 | access to local variable o : Object | | F.cs:11:17:11:31 | call to method Create [Field1] : Object | F.cs:12:14:12:14 | access to local variable f [Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create [Field1] : Object | | F.cs:12:14:12:14 | access to local variable f [Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | | F.cs:15:13:15:27 | call to method Create [Field2] : Object | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | | F.cs:15:26:15:26 | access to local variable o : Object | F.cs:15:13:15:27 | call to method Create [Field2] : Object | | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | -| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:13:19:34 | object creation of type F [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:23:32:23:32 | access to local variable o : Object | +| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | +| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | -| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | -| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:13:23:34 | object creation of type F [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | +| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | | G.cs:7:18:7:27 | object creation of type Elem : Elem | G.cs:9:23:9:23 | access to local variable e : Elem | | G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] | G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | @@ -201,7 +201,8 @@ edges | H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:147:17:147:32 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | | H.cs:147:25:147:31 | object creation of type A : A | H.cs:147:17:147:32 | call to method Through : A | -| H.cs:155:17:155:23 | object creation of type B : B | H.cs:157:20:157:20 | access to local variable b : B | +| H.cs:155:17:155:23 | object creation of type B : B | H.cs:156:9:156:9 | access to local variable b : B | +| H.cs:156:9:156:9 | access to local variable b : B | H.cs:157:20:157:20 | access to local variable b : B | | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:164:22:164:22 | access to local variable o : Object | @@ -215,6 +216,28 @@ edges | H.cs:165:21:165:28 | access to field FieldA : B | H.cs:165:17:165:28 | (...) ... : B | | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:21:13:21:19 | object creation of type I [Field1] : Object | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | +| I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:7:9:7:14 | [post] this access [Field1] : Object | +| I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:15:20:15:20 | access to local variable o : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | I.cs:16:9:16:9 | access to local variable i [Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | I.cs:17:9:17:9 | access to local variable i [Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | I.cs:22:9:22:9 | access to local variable i [Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | I.cs:23:14:23:14 | access to local variable i [Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | +| I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:32:20:32:20 | access to local variable o : Object | +| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | I.cs:33:9:33:9 | access to local variable i [Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | I.cs:34:12:34:12 | access to local variable i [Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | I.cs:37:23:37:23 | i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:39:9:39:9 | access to parameter i [Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | nodes | A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C | | A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C | @@ -367,11 +390,11 @@ nodes | F.cs:15:26:15:26 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | | F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 | -| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | semmle.label | object creation of type F [Field1] : Object | +| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | semmle.label | { ..., ... } [Field1] : Object | | F.cs:19:32:19:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | semmle.label | access to local variable f [Field1] : Object | | F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 | -| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | semmle.label | object creation of type F [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | semmle.label | { ..., ... } [Field2] : Object | | F.cs:23:32:23:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | | F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 | @@ -449,6 +472,7 @@ nodes | H.cs:147:25:147:31 | object creation of type A : A | semmle.label | object creation of type A : A | | H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | | H.cs:155:17:155:23 | object creation of type B : B | semmle.label | object creation of type B : B | +| H.cs:156:9:156:9 | access to local variable b : B | semmle.label | access to local variable b : B | | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | semmle.label | [post] access to parameter a [FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | | H.cs:163:17:163:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | @@ -464,6 +488,31 @@ nodes | H.cs:166:14:166:14 | access to local variable b | semmle.label | access to local variable b | | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | | H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | semmle.label | [post] this access [Field1] : Object | +| I.cs:7:18:7:29 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:13:17:13:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | semmle.label | [pre-initializer] object creation of type I [Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:31:13:31:24 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | semmle.label | i [Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | #select | A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 | @@ -513,3 +562,7 @@ nodes | H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:31 | object creation of type A : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A | | H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:23 | object creation of type B : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:23 | object creation of type B : B | object creation of type B : B | | H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/fields/I.cs b/csharp/ql/test/library-tests/dataflow/fields/I.cs new file mode 100644 index 00000000000..99aed3b0df7 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/fields/I.cs @@ -0,0 +1,46 @@ +public class I +{ + object Field1; + object Field2; + public I() + { + Field1 = new object(); + Field2 = new object(); + } + + private void M() + { + var o = new object(); + var i = new I(); + i.Field1 = o; + i.Field2 = o; + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I(); + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I() { Field2 = null }; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I(); + o = new object(); + i.Field1 = o; + i.Field2 = o; + M2(i); + } + + private void M2(I i) + { + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + } + + public static void Sink(object o) { } +} diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index ca81fb55904..0c73bf55b63 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -12,31 +12,45 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index a46026ba3da..fa8e90c97e9 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -1,189 +1,221 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| 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:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:422:9:422:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -205,147 +237,182 @@ edges | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| 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:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -371,19 +438,27 @@ nodes | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | | Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | | Capture.cs:72:15:72:20 | access to local variable sink30 | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:72:15:72:20 | access to local variable sink30 | access to local variable sink30 | | Capture.cs:84:15:84:20 | access to local variable sink31 | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:84:15:84:20 | access to local variable sink31 | access to local variable sink31 | | Capture.cs:93:15:93:20 | access to local variable sink32 | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:93:15:93:20 | access to local variable sink32 | access to local variable sink32 | @@ -393,23 +468,29 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | | Capture.cs:122:15:122:20 | access to local variable sink40 | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:122:15:122:20 | access to local variable sink40 | access to local variable sink40 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x | | Capture.cs:57:27:57:32 | access to parameter sink39 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:57:27:57:32 | access to parameter sink39 | access to parameter sink39 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | | Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 2b712d5c2f8..088eefba975 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -25,170 +25,174 @@ | Capture.cs:191:20:191:22 | call to local function M | return | Capture.cs:191:20:191:22 | call to local function M | | Capture.cs:194:22:194:32 | call to local function Id | return | Capture.cs:194:22:194:32 | call to local function Id | | Capture.cs:196:20:196:25 | call to local function Id | return | Capture.cs:196:20:196:25 | call to local function Id | -| GlobalDataFlow.cs:25:9:25:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:25:9:25:26 | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | return | GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | return | GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | return | GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | return | GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return | return | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | return | GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | return | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | out | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | out | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:93 | call to method First | return | GlobalDataFlow.cs:80:22:80:93 | call to method First | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:95 | call to method First | return | GlobalDataFlow.cs:82:22:82:95 | call to method First | -| GlobalDataFlow.cs:82:76:82:86 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:136 | call to method First | return | GlobalDataFlow.cs:84:22:84:136 | call to method First | -| GlobalDataFlow.cs:84:117:84:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:136 | call to method First | return | GlobalDataFlow.cs:86:22:86:136 | call to method First | -| GlobalDataFlow.cs:86:117:86:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | -| GlobalDataFlow.cs:88:83:88:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... | -| GlobalDataFlow.cs:88:104:88:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | -| GlobalDataFlow.cs:90:83:90:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... | -| GlobalDataFlow.cs:90:104:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | out | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | ref | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | return | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | out | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | ref | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | return | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return | return | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | return | GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | return | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | out | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:106:9:106:49 | call to method ReturnOut | out | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | out | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | out | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:94 | call to method First | return | GlobalDataFlow.cs:112:20:112:94 | call to method First | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | yield return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:90 | call to method First | return | GlobalDataFlow.cs:114:20:114:90 | call to method First | -| GlobalDataFlow.cs:114:76:114:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:134 | call to method First | return | GlobalDataFlow.cs:116:20:116:134 | call to method First | -| GlobalDataFlow.cs:116:115:116:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:115:116:125 | [output] (...) => ... | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:134 | call to method First | return | GlobalDataFlow.cs:118:20:118:134 | call to method First | -| GlobalDataFlow.cs:118:115:118:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:115:118:125 | [output] (...) => ... | -| GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | -| GlobalDataFlow.cs:120:81:120:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:81:120:95 | [output] (...) => ... | -| GlobalDataFlow.cs:120:98:120:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:98:120:103 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | -| GlobalDataFlow.cs:122:81:122:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:81:122:99 | [output] (...) => ... | -| GlobalDataFlow.cs:122:102:122:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:102:122:108 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | -| GlobalDataFlow.cs:124:86:124:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:86:124:98 | [output] (...) => ... | -| GlobalDataFlow.cs:124:101:124:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:101:124:106 | [output] (...) => ... | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | out | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | ref | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | return | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | out | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | ref | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | return | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:135:21:135:34 | delegate call | return | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:139:20:139:36 | delegate call | return | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out | return | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | out | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | ref | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | out | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | ref | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | yield return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:39 | call to method First | return | GlobalDataFlow.cs:161:22:161:39 | call to method First | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | return | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | return | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | out | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | out | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:40 | call to method First | return | GlobalDataFlow.cs:173:20:173:40 | call to method First | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:180:21:180:26 | delegate call | return | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:185:20:185:27 | delegate call | return | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy | return | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value | return | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy | return | GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value | return | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | return | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | return | GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | -| GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | return | GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | -| GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | yield return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:47 | call to method First | return | GlobalDataFlow.cs:212:22:212:47 | call to method First | -| GlobalDataFlow.cs:212:37:212:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:214:22:214:39 | call to method Select | return | GlobalDataFlow.cs:214:22:214:39 | call to method Select | -| GlobalDataFlow.cs:214:22:214:47 | call to method First | return | GlobalDataFlow.cs:214:22:214:47 | call to method First | -| GlobalDataFlow.cs:214:37:214:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | yield return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:57 | call to method First | return | GlobalDataFlow.cs:216:22:216:57 | call to method First | -| GlobalDataFlow.cs:216:37:216:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | yield return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:51 | call to method First | return | GlobalDataFlow.cs:222:23:222:51 | call to method First | -| GlobalDataFlow.cs:222:41:222:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:222:41:222:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select | return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:19:224:47 | call to method First | return | GlobalDataFlow.cs:224:19:224:47 | call to method First | -| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | yield return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:47 | call to method First | return | GlobalDataFlow.cs:226:19:226:47 | call to method First | -| GlobalDataFlow.cs:226:37:226:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:228:19:228:39 | call to method Select | return | GlobalDataFlow.cs:228:19:228:39 | call to method Select | -| GlobalDataFlow.cs:228:19:228:47 | call to method First | return | GlobalDataFlow.cs:228:19:228:47 | call to method First | -| GlobalDataFlow.cs:228:37:228:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:228:37:228:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | yield return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:57 | call to method First | return | GlobalDataFlow.cs:230:19:230:57 | call to method First | -| GlobalDataFlow.cs:230:37:230:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:230:37:230:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:368:16:368:19 | delegate call | return | GlobalDataFlow.cs:368:16:368:19 | delegate call | -| GlobalDataFlow.cs:433:44:433:47 | delegate call | return | GlobalDataFlow.cs:433:44:433:47 | delegate call | +| GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | return | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | return | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | return | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | +| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | return | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return | return | GlobalDataFlow.cs:71:21:71:46 | call to method Return | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | return | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | return | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | out | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | +| GlobalDataFlow.cs:81:22:81:93 | call to method First | return | GlobalDataFlow.cs:81:22:81:93 | call to method First | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select | return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select | yield return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | +| GlobalDataFlow.cs:83:22:83:95 | call to method First | return | GlobalDataFlow.cs:83:22:83:95 | call to method First | +| GlobalDataFlow.cs:83:76:83:86 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:83:76:83:86 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | yield return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | +| GlobalDataFlow.cs:85:22:85:136 | call to method First | return | GlobalDataFlow.cs:85:22:85:136 | call to method First | +| GlobalDataFlow.cs:85:117:85:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:85:117:85:127 | [output] (...) => ... | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | yield return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | +| GlobalDataFlow.cs:87:22:87:136 | call to method First | return | GlobalDataFlow.cs:87:22:87:136 | call to method First | +| GlobalDataFlow.cs:87:117:87:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:87:117:87:127 | [output] (...) => ... | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | +| GlobalDataFlow.cs:89:83:89:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:83:89:101 | [output] (...) => ... | +| GlobalDataFlow.cs:89:104:89:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:104:89:109 | [output] (...) => ... | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | +| GlobalDataFlow.cs:91:83:91:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:83:91:101 | [output] (...) => ... | +| GlobalDataFlow.cs:91:104:91:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:104:91:109 | [output] (...) => ... | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | out | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | ref | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | return | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | out | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | return | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | +| GlobalDataFlow.cs:101:24:101:33 | call to method Return | return | GlobalDataFlow.cs:101:24:101:33 | call to method Return | +| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | return | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | +| GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | return | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | out | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | out | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | +| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | +| GlobalDataFlow.cs:113:20:113:94 | call to method First | return | GlobalDataFlow.cs:113:20:113:94 | call to method First | +| GlobalDataFlow.cs:115:20:115:82 | call to method Select | return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | +| GlobalDataFlow.cs:115:20:115:82 | call to method Select | yield return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | +| GlobalDataFlow.cs:115:20:115:90 | call to method First | return | GlobalDataFlow.cs:115:20:115:90 | call to method First | +| GlobalDataFlow.cs:115:76:115:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:115:76:115:81 | [output] (...) => ... | +| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | +| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | yield return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | +| GlobalDataFlow.cs:117:20:117:134 | call to method First | return | GlobalDataFlow.cs:117:20:117:134 | call to method First | +| GlobalDataFlow.cs:117:115:117:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:117:115:117:125 | [output] (...) => ... | +| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | +| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | yield return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | +| GlobalDataFlow.cs:119:20:119:134 | call to method First | return | GlobalDataFlow.cs:119:20:119:134 | call to method First | +| GlobalDataFlow.cs:119:115:119:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:119:115:119:125 | [output] (...) => ... | +| GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | +| GlobalDataFlow.cs:121:81:121:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:81:121:95 | [output] (...) => ... | +| GlobalDataFlow.cs:121:98:121:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:98:121:103 | [output] (...) => ... | +| GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | +| GlobalDataFlow.cs:123:81:123:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:81:123:99 | [output] (...) => ... | +| GlobalDataFlow.cs:123:102:123:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:102:123:108 | [output] (...) => ... | +| GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | return | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | +| GlobalDataFlow.cs:125:86:125:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:86:125:98 | [output] (...) => ... | +| GlobalDataFlow.cs:125:101:125:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:101:125:106 | [output] (...) => ... | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | out | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | ref | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | return | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | out | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | ref | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | return | GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | +| GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | +| GlobalDataFlow.cs:136:21:136:34 | delegate call | return | GlobalDataFlow.cs:136:21:136:34 | delegate call | +| GlobalDataFlow.cs:140:20:140:36 | delegate call | return | GlobalDataFlow.cs:140:20:140:36 | delegate call | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | +| GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out | return | GlobalDataFlow.cs:154:21:154:25 | call to method Out | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | yield return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | +| GlobalDataFlow.cs:162:22:162:39 | call to method First | return | GlobalDataFlow.cs:162:22:162:39 | call to method First | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | return | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | +| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | return | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | +| GlobalDataFlow.cs:174:20:174:40 | call to method First | return | GlobalDataFlow.cs:174:20:174:40 | call to method First | +| GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | +| GlobalDataFlow.cs:181:21:181:26 | delegate call | return | GlobalDataFlow.cs:181:21:181:26 | delegate call | +| GlobalDataFlow.cs:186:20:186:27 | delegate call | return | GlobalDataFlow.cs:186:20:186:27 | delegate call | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | return | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | return | GlobalDataFlow.cs:190:22:190:48 | access to property Value | +| GlobalDataFlow.cs:190:39:190:41 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:190:39:190:41 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | return | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | return | GlobalDataFlow.cs:194:20:194:49 | access to property Value | +| GlobalDataFlow.cs:194:37:194:42 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:194:37:194:42 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | return | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | +| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | return | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | +| GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | return | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | +| GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select | return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select | yield return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | +| GlobalDataFlow.cs:213:22:213:47 | call to method First | return | GlobalDataFlow.cs:213:22:213:47 | call to method First | +| GlobalDataFlow.cs:213:37:213:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:213:37:213:38 | [output] access to local variable f1 | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select | return | GlobalDataFlow.cs:215:22:215:39 | call to method Select | +| GlobalDataFlow.cs:215:22:215:47 | call to method First | return | GlobalDataFlow.cs:215:22:215:47 | call to method First | +| GlobalDataFlow.cs:215:37:215:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:215:37:215:38 | [output] access to local variable f2 | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select | return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select | yield return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | +| GlobalDataFlow.cs:217:22:217:57 | call to method First | return | GlobalDataFlow.cs:217:22:217:57 | call to method First | +| GlobalDataFlow.cs:217:37:217:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:217:37:217:48 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | +| GlobalDataFlow.cs:223:23:223:43 | call to method Select | return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | +| GlobalDataFlow.cs:223:23:223:43 | call to method Select | yield return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | +| GlobalDataFlow.cs:223:23:223:51 | call to method First | return | GlobalDataFlow.cs:223:23:223:51 | call to method First | +| GlobalDataFlow.cs:223:41:223:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:223:41:223:42 | [output] access to local variable f1 | +| GlobalDataFlow.cs:225:19:225:39 | call to method Select | return | GlobalDataFlow.cs:225:19:225:39 | call to method Select | +| GlobalDataFlow.cs:225:19:225:47 | call to method First | return | GlobalDataFlow.cs:225:19:225:47 | call to method First | +| GlobalDataFlow.cs:225:37:225:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:225:37:225:38 | [output] access to local variable f2 | +| GlobalDataFlow.cs:227:19:227:39 | call to method Select | return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | +| GlobalDataFlow.cs:227:19:227:39 | call to method Select | yield return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | +| GlobalDataFlow.cs:227:19:227:47 | call to method First | return | GlobalDataFlow.cs:227:19:227:47 | call to method First | +| GlobalDataFlow.cs:227:37:227:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:227:37:227:38 | [output] access to local variable f3 | +| GlobalDataFlow.cs:229:19:229:39 | call to method Select | return | GlobalDataFlow.cs:229:19:229:39 | call to method Select | +| GlobalDataFlow.cs:229:19:229:47 | call to method First | return | GlobalDataFlow.cs:229:19:229:47 | call to method First | +| GlobalDataFlow.cs:229:37:229:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:229:37:229:38 | [output] access to local variable f4 | +| GlobalDataFlow.cs:231:19:231:49 | call to method Select | return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | +| GlobalDataFlow.cs:231:19:231:49 | call to method Select | yield return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | +| GlobalDataFlow.cs:231:19:231:57 | call to method First | return | GlobalDataFlow.cs:231:19:231:57 | call to method First | +| GlobalDataFlow.cs:231:37:231:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:231:37:231:48 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:238:22:238:51 | call to method Run | return | GlobalDataFlow.cs:238:22:238:51 | call to method Run | +| GlobalDataFlow.cs:238:31:238:50 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:238:31:238:50 | [output] (...) => ... | +| GlobalDataFlow.cs:244:24:244:41 | call to method Run | return | GlobalDataFlow.cs:244:24:244:41 | call to method Run | +| GlobalDataFlow.cs:244:33:244:40 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:244:33:244:40 | [output] (...) => ... | +| GlobalDataFlow.cs:295:17:295:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:295:17:295:38 | call to method ApplyFunc | +| GlobalDataFlow.cs:384:16:384:19 | delegate call | return | GlobalDataFlow.cs:384:16:384:19 | delegate call | +| GlobalDataFlow.cs:449:44:449:47 | delegate call | return | GlobalDataFlow.cs:449:44:449:47 | delegate call | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | | Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return | diff --git a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs index 83003aaea66..897f56d24e5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -2,6 +2,7 @@ using System; using System.Text; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; /// /// All (tainted) sinks are named `sink[Param|Field|Property]N`, for some N, and all @@ -231,6 +232,21 @@ public class DataFlow Check(nonSink); } + public async void M3() + { + // async await, tainted + var sink41 = Task.Run(() => "taint source"); + Check(sink41); + var sink42 = await sink41; + Check(sink42); + + // async await, not tainted + var nonSink0 = Task.Run(() => ""); + Check(nonSink0); + var nonSink1 = await nonSink0; + Check(nonSink1); + } + static void Check(T x) { } static void In0(T sinkParam0) diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 57fd2c9e0c3..fa619f3ddac 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -12,47 +12,49 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index c0422a5f0f5..6dccf5b7da1 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -1,239 +1,228 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| 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 | (...) ... : 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 | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:211:71:211:71 | x : String | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:422:9:422:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -246,9 +235,6 @@ edges | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | @@ -258,199 +244,189 @@ edges | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| 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 | semmle.label | call to method SelectEven : IEnumerable | -| 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:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [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:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [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:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | semmle.label | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | semmle.label | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | semmle.label | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | semmle.label | yield return ...; : IEnumerable | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -486,47 +462,49 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs index f6bf395eef2..e6aea19d9c0 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs @@ -45,6 +45,7 @@ public class LibraryTypeDataFlow ieint.Select(x => x); List list = null; list.Find(x => x > 0); + list.Insert(0, 0); Stack stack = null; stack.Peek(); ArrayList al = null; @@ -83,6 +84,8 @@ public class LibraryTypeDataFlow Path.GetPathRoot(""); HttpContextBase context = null; string name = context.Request.QueryString["name"]; + + var dict = new Dictionary() { {"abc", 0 } }; } [DataContract] diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 6769e2a1411..b2c649eab75 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1,223 +1,7 @@ callableFlow -| LibraryTypeDataFlow.DataContract.get_AString() | qualifier -> return | false | -| System.Array.Add(object) | argument 0 -> qualifier | false | -| System.Array.AsReadOnly(T[]) | qualifier -> return | false | -| System.Array.Clone() | qualifier -> return | false | -| System.Array.Find(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.Find(T[], Predicate) | argument 0 -> return | false | -| System.Array.FindAll(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindAll(T[], Predicate) | argument 0 -> return | false | -| System.Array.FindLast(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindLast(T[], Predicate) | argument 0 -> return | false | -| System.Array.GetEnumerator() | qualifier -> return | false | -| System.Array.Insert(int, object) | argument 1 -> qualifier | false | -| System.Array.Reverse(Array) | qualifier -> return | false | -| System.Array.Reverse(Array, int, int) | qualifier -> return | false | -| System.Array.Reverse(T[]) | qualifier -> return | false | -| System.Array.Reverse(T[], int, int) | qualifier -> return | false | | System.Boolean.Parse(string) | argument 0 -> return | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> argument 1 | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> return | false | -| System.Collections.ArrayList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.AddRange(ICollection) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.Clone() | qualifier -> return | false | -| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 -> return | false | -| System.Collections.ArrayList.FixedSize(IList) | argument 0 -> return | false | -| System.Collections.ArrayList.GetEnumerator() | qualifier -> return | false | -| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.GetRange(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.Reverse() | qualifier -> return | false | -| System.Collections.ArrayList.Reverse(int, int) | qualifier -> return | false | -| System.Collections.BitArray.Clone() | qualifier -> return | false | -| System.Collections.BitArray.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Add(object) | argument 0 -> qualifier | false | -| System.Collections.CollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T, CancellationToken) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.DictionaryBase.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.DictionaryBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.HashSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.ICollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.IEnumerable<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.IEnumerator<>.get_Current() | qualifier -> return | true | -| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.IReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.ISet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 -> return | true | -| System.Collections.Generic.KeyValuePair<,>.get_Value() | qualifier -> return | true | -| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.LinkedList<>.Find(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AddRange(IEnumerable) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AsReadOnly() | qualifier -> return | false | -| System.Collections.Generic.List<>.Find(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.Find(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.GetRange(int, int) | qualifier -> return | false | -| System.Collections.Generic.List<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.List<>.Reverse(int, int) | qualifier -> return | false | -| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Queue<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Pop() | qualifier -> return | false | -| System.Collections.Hashtable.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Hashtable.Clone() | qualifier -> return | false | -| System.Collections.Hashtable.GetEnumerator() | qualifier -> return | false | -| System.Collections.Hashtable.get_Values() | qualifier -> return | false | -| System.Collections.IDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.IDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.IDictionary.get_Values() | qualifier -> return | false | -| System.Collections.IEnumerable.GetEnumerator() | qualifier -> return | false | -| System.Collections.IEnumerator.get_Current() | qualifier -> return | true | -| System.Collections.IList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.IList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier -> return | false | -| System.Collections.ListDictionaryInternal.get_Values() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Queue.Clone() | qualifier -> return | false | -| System.Collections.Queue.GetEnumerator() | qualifier -> return | false | -| System.Collections.Queue.Peek() | qualifier -> return | false | -| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.SortedList.Clone() | qualifier -> return | false | -| System.Collections.SortedList.GetByIndex(int) | qualifier -> return | false | -| System.Collections.SortedList.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.GetValueList() | qualifier -> return | false | -| System.Collections.SortedList.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.IOrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 -> qualifier | false | -| System.Collections.Specialized.NameValueCollection.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Add(string) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Stack.Clone() | qualifier -> return | false | -| System.Collections.Stack.GetEnumerator() | qualifier -> return | false | -| System.Collections.Stack.Peek() | qualifier -> return | false | -| System.Collections.Stack.Pop() | qualifier -> return | false | -| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier -> return | false | | System.Convert.ChangeType(object, Type) | argument 0 -> return | false | | System.Convert.ChangeType(object, Type, IFormatProvider) | argument 0 -> return | false | | System.Convert.ChangeType(object, TypeCode) | argument 0 -> return | false | @@ -532,10 +316,6 @@ callableFlow | System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | argument 0 -> return | false | | System.Convert.TryFromBase64String(string, Span, out int) | argument 0 -> return | false | | System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | argument 0 -> return | false | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 -> qualifier | false | -| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier -> return | false | -| System.ICloneable.Clone() | qualifier -> return | false | | System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.BufferedStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | @@ -662,644 +442,44 @@ callableFlow | System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return | false | | System.Int32.TryParse(string, out int) | argument 0 -> argument 1 | false | | System.Int32.TryParse(string, out int) | argument 0 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 3 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.AsEnumerable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Cast(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return | false | -| System.Linq.Enumerable.Distinct(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAt(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.First(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Last(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OfType(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Reverse(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Single(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Skip(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Take(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ToArray(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ToList(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | output from argument 2 -> return | false | -| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Add(TElement) | argument 0 -> qualifier | false | -| System.Linq.Grouping<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 -> qualifier | false | -| System.Linq.Lookup<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.OrderedParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelQuery.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Cast(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return | false | -| System.Linq.Queryable.Distinct(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAt(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.Except(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.First(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | output from argument 4 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Queryable.Last(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OfType(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Reverse(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Single(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Skip(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Take(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 -> return | false | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 3 -> return | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | output from argument 2 -> return | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | output from argument 1 -> return | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 3 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | output from argument 2 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | output from argument 1 -> return | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | | System.Net.Cookie.get_Value() | qualifier -> return | false | -| System.Net.CookieCollection.Add(Cookie) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.Add(CookieCollection) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.CredentialCache.GetEnumerator() | qualifier -> return | false | -| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 -> qualifier | false | -| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 -> qualifier | false | -| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier -> return | false | | System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Net.Security.NegotiateStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | @@ -1313,29 +493,13 @@ callableFlow | System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false | | System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false | | System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false | -| System.Object.ToString() | qualifier -> return | false | -| System.Resources.IResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceSet.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | qualifier -> return | false | | System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.Security.PermissionSet.GetEnumerator() | qualifier -> return | false | -| System.String.Clone() | qualifier -> return | false | | System.String.Clone() | qualifier -> return | true | -| System.String.Concat(IEnumerable) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 1 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 0 -> return | false | @@ -1360,7 +524,6 @@ callableFlow | System.String.Concat(string, string, string, string) | argument 1 -> return | false | | System.String.Concat(string, string, string, string) | argument 2 -> return | false | | System.String.Concat(string, string, string, string) | argument 3 -> return | false | -| System.String.Concat(IEnumerable) | argument 0 -> return | false | | System.String.Copy(string) | argument 0 -> return | true | | System.String.Format(IFormatProvider, string, object) | argument 1 -> return | false | | System.String.Format(IFormatProvider, string, object) | argument 2 -> return | false | @@ -1371,6 +534,7 @@ callableFlow | System.String.Format(IFormatProvider, string, object, object, object) | argument 2 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 3 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 4 -> return | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 1 -> return | false | | System.String.Format(string, object) | argument 0 -> return | false | | System.String.Format(string, object) | argument 1 -> return | false | | System.String.Format(string, object, object) | argument 0 -> return | false | @@ -1380,21 +544,18 @@ callableFlow | System.String.Format(string, object, object, object) | argument 1 -> return | false | | System.String.Format(string, object, object, object) | argument 2 -> return | false | | System.String.Format(string, object, object, object) | argument 3 -> return | false | -| System.String.GetEnumerator() | qualifier -> return | false | +| System.String.Format(string, params Object[]) | argument 0 -> return | false | | System.String.Insert(int, string) | argument 1 -> return | false | | System.String.Insert(int, string) | qualifier -> return | false | +| System.String.Join(char, String[], int, int) | argument 0 -> return | false | +| System.String.Join(char, params Object[]) | argument 0 -> return | false | +| System.String.Join(char, params String[]) | argument 0 -> return | false | | System.String.Join(string, IEnumerable) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable) | argument 1 -> return | false | | System.String.Join(string, String[], int, int) | argument 0 -> return | false | -| System.String.Join(string, String[], int, int) | argument 1 -> return | false | -| System.String.Join(string, String[], int, int) | argument 2 -> return | false | -| System.String.Join(string, String[], int, int) | argument 3 -> return | false | +| System.String.Join(string, params Object[]) | argument 0 -> return | false | | System.String.Join(string, params String[]) | argument 0 -> return | false | -| System.String.Join(string, params String[]) | argument 1 -> return | false | -| System.String.Join(string, params String[]) | argument 2 -> return | false | -| System.String.Join(string, params String[]) | argument 3 -> return | false | +| System.String.Join(char, IEnumerable) | argument 0 -> return | false | | System.String.Join(string, IEnumerable) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable) | argument 1 -> return | false | | System.String.Normalize() | qualifier -> return | false | | System.String.Normalize(NormalizationForm) | qualifier -> return | false | | System.String.PadLeft(int) | qualifier -> return | false | @@ -1407,24 +568,13 @@ callableFlow | System.String.Replace(char, char) | qualifier -> return | false | | System.String.Replace(string, string) | argument 1 -> return | false | | System.String.Replace(string, string) | qualifier -> return | false | -| System.String.Split(Char[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(Char[], int) | qualifier -> return | false | -| System.String.Split(Char[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(params Char[]) | qualifier -> return | false | -| System.String.Split(string, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(string, int, StringSplitOptions) | qualifier -> return | false | -| System.String.String(Char[]) | argument 0 -> return | false | -| System.String.String(Char[], int, int) | argument 0 -> return | false | | System.String.Substring(int) | qualifier -> return | false | | System.String.Substring(int, int) | qualifier -> return | false | | System.String.ToLower() | qualifier -> return | false | | System.String.ToLower(CultureInfo) | qualifier -> return | false | | System.String.ToLowerInvariant() | qualifier -> return | false | | System.String.ToString() | qualifier -> return | true | +| System.String.ToString(IFormatProvider) | qualifier -> return | true | | System.String.ToUpper() | qualifier -> return | false | | System.String.ToUpper(CultureInfo) | qualifier -> return | false | | System.String.ToUpperInvariant() | qualifier -> return | false | @@ -1437,65 +587,11 @@ callableFlow | System.String.TrimStart() | qualifier -> return | false | | System.String.TrimStart(char) | qualifier -> return | false | | System.String.TrimStart(params Char[]) | qualifier -> return | false | -| System.Text.Encoding.GetBytes(Char[]) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 -> return | false | -| System.Text.Encoding.GetString(byte*, int) | argument 0 -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.get_Values() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.Append(object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string, int, int) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendLine(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.StringBuilder(string) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 -> return | false | -| System.Text.StringBuilder.ToString() | qualifier -> return | false | | System.Threading.Tasks.Task.ContinueWith(Action, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | @@ -1525,12 +621,6 @@ callableFlow | System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 1 -> return | true | -| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 1 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | @@ -1684,6 +774,1296 @@ callableFlow | System.Web.HttpUtility.UrlEncode(string) | argument 0 -> return | false | | System.Web.UI.WebControls.TextBox.get_Text() | qualifier -> return | false | callableFlowAccessPath -| System.Lazy<>.Lazy(Func) | output from argument 0 [] -> return [Value] | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 [] -> return [Value] | -| System.Lazy<>.Lazy(Func, bool) | output from argument 0 [] -> return [Value] | +| System.Array.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Array.AsReadOnly(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Array.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.CopyTo(Array, long) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.Find(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.Find(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.FindAll(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.FindAll(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.FindLast(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.FindLast(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Array.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Array.Reverse(Array) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(Array, int, int) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(T[], int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ArrayList.AddRange(ICollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.FixedSize(IList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Repeat(object, int) | argument 0 [] -> return [[]] | true | +| System.Collections.ArrayList.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ArrayList.set_Item(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.BitArray.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.BitArray.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.BitArray.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.CollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.CollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | argument 1 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | argument 1 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.DictionaryBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.Dictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.HashSet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.ICollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.IDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.IList<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.IList<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.ISet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 0 [] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 1 [] -> return [Value] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 0 [] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 [] -> return [Value] | true | +| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.Find(T) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AddRange(IEnumerable) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.Find(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.Find(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Queue<>.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.SortedList<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedSet<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Stack<>.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Generic.Stack<>.Pop() | qualifier [[]] -> return [] | true | +| System.Collections.Hashtable.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Hashtable.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Hashtable.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Hashtable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Hashtable.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Hashtable.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ICollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.IDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.IDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.IDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.IDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.IEnumerable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.IList.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.IList.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.IList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.IList.set_Item(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ListDictionaryInternal.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.ListDictionaryInternal.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Queue.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Queue.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Queue.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Queue.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.SortedList.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.SortedList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.SortedList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.SortedList.GetByIndex(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.SortedList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.GetValueList() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.SortedList.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.SortedList.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.HybridDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.HybridDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.ListDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.ListDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.OrderedDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.StringCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Add(string) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Specialized.StringCollection.set_Item(int, string) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Stack.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Stack.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Stack.Pop() | qualifier [[]] -> return [] | true | +| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [] | true | +| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier [[]] -> return [] | true | +| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[], Value] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.IO.Path.Combine(params String[]) | argument 0 [[]] -> return [] | false | +| System.Lazy<>.Lazy(Func) | output from argument 0 [] -> return [Value] | true | +| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 [] -> return [Value] | true | +| System.Lazy<>.Lazy(Func, bool) | output from argument 0 [] -> return [Value] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.AsEnumerable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Cast(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Distinct(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ElementAt(IEnumerable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.First(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Last(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OfType(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Reverse(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.Single(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Skip(IEnumerable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Take(IEnumerable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToArray(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToList(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Add(TElement) | argument 0 [] -> qualifier [[]] | true | +| System.Linq.Grouping<,>.CopyTo(TElement[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Linq.Grouping<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 [] -> qualifier [[]] | true | +| System.Linq.Lookup<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelQuery.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Cast(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Distinct(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ElementAt(IQueryable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.First(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Last(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OfType(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Reverse(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.Single(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Skip(IQueryable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Take(IQueryable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Net.CookieCollection.Add(Cookie) | argument 0 [] -> qualifier [[]] | true | +| System.Net.CookieCollection.Add(CookieCollection) | argument 0 [] -> qualifier [[]] | true | +| System.Net.CookieCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.CopyTo(Cookie[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.CredentialCache.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 [] -> qualifier [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 [] -> qualifier [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Security.PermissionSet.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Security.PermissionSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Concat(IEnumerable) | argument 0 [[]] -> return [] | false | +| System.String.Concat(params Object[]) | argument 0 [[]] -> return [] | false | +| System.String.Concat(params String[]) | argument 0 [[]] -> return [] | false | +| System.String.Concat(IEnumerable) | argument 0 [[]] -> return [] | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 2 [[]] -> return [] | false | +| System.String.Format(string, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Join(char, String[], int, int) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, params String[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, String[], int, int) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, params String[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Split(Char[], StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(Char[], int) | qualifier [] -> return [[]] | false | +| System.String.Split(Char[], int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(String[], StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(String[], int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(char, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(char, int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(params Char[]) | qualifier [] -> return [[]] | false | +| System.String.Split(string, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(string, int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.String(Char[]) | argument 0 [[]] -> return [] | false | +| System.String.String(Char[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(Byte[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(byte*, int) | argument 0 [[]] -> return [] | false | +| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.ToString() | qualifier [[]] -> return [] | false | +| System.Text.StringBuilder.ToString(int, int) | qualifier [[]] -> return [] | false | +| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | argument 0 [[]] -> return [] | true | +| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 0 [[]] -> return [] | true | +| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | argument 0 [[]] -> return [] | true | +| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 0 [[]] -> return [] | true | +clearsContent +| System.Array.Clear() | qualifier | [] | +| System.Array.Clear(Array, int, int) | qualifier | [] | +| System.Collections.ArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeList.Clear() | qualifier | [] | +| System.Collections.ArrayList.IListWrapper.Clear() | qualifier | [] | +| System.Collections.ArrayList.Range.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncIList.Clear() | qualifier | [] | +| System.Collections.CollectionBase.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentBag<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentQueue<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentStack<>.Clear() | qualifier | [] | +| System.Collections.DictionaryBase.Clear() | qualifier | [] | +| System.Collections.EmptyReadOnlyDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.HashSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.ICollection<>.Clear() | qualifier | [] | +| System.Collections.Generic.LinkedList<>.Clear() | qualifier | [] | +| System.Collections.Generic.List<>.Clear() | qualifier | [] | +| System.Collections.Generic.Queue<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.KeyList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.ValueList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.TreeSubSet.Clear() | qualifier | [] | +| System.Collections.Generic.Stack<>.Clear() | qualifier | [] | +| System.Collections.Hashtable.Clear() | qualifier | [] | +| System.Collections.Hashtable.SyncHashtable.Clear() | qualifier | [] | +| System.Collections.IDictionary.Clear() | qualifier | [] | +| System.Collections.IList.Clear() | qualifier | [] | +| System.Collections.ListDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.ObjectModel.Collection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Queue.Clear() | qualifier | [] | +| System.Collections.Queue.SynchronizedQueue.Clear() | qualifier | [] | +| System.Collections.SortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.KeyList.Clear() | qualifier | [] | +| System.Collections.SortedList.SyncSortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.ValueList.Clear() | qualifier | [] | +| System.Collections.Specialized.HybridDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ListDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.NameValueCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.OrderedDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.Specialized.StringCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.StringDictionary.Clear() | qualifier | [] | +| System.Collections.Stack.Clear() | qualifier | [] | +| System.Collections.Stack.SyncStack.Clear() | qualifier | [] | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.EventDescriptorCollection.Clear() | qualifier | [] | +| System.ComponentModel.ListSortDescriptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.PropertyDescriptorCollection.Clear() | qualifier | [] | +| System.Diagnostics.Tracing.EventPayload.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.KeyCollection.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.ValueCollection.Clear() | qualifier | [] | +| System.Dynamic.Utils.ListProvider<>.Clear() | qualifier | [] | +| System.Linq.Expressions.BlockExpressionList.Clear() | qualifier | [] | +| System.Linq.Grouping<,>.Clear() | qualifier | [] | +| System.Linq.Parallel.QueryResults<>.Clear() | qualifier | [] | +| System.Net.CookieCollection.Clear() | qualifier | [] | +| System.Net.HttpListenerPrefixCollection.Clear() | qualifier | [] | +| System.Net.NetworkInformation.IPAddressCollection.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Clear() | qualifier | [] | +| System.Text.RegularExpressions.CaptureCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.GroupCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.MatchCollection.Clear() | qualifier | [] | +| System.Text.StringBuilder.Clear() | qualifier | [] | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql index a5d65c711a3..fa11e138d1f 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql @@ -1,27 +1,43 @@ +import csharp import semmle.code.csharp.dataflow.LibraryTypeDataFlow query predicate callableFlow(string callable, string flow, boolean preservesValue) { exists(LibraryTypeDataFlow x, CallableFlowSource source, CallableFlowSink sink, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sink, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " -> " + sink and // Remove certain results to make the test output consistent // between different versions of .NET Core. not callable = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" + | + x.callableFlow(source, sink, c, preservesValue) + or + x.callableFlow(source, AccessPath::empty(), sink, AccessPath::empty(), c, preservesValue) ) } -query predicate callableFlowAccessPath(string callable, string flow) { +query predicate callableFlowAccessPath(string callable, string flow, boolean preservesValue) { exists( LibraryTypeDataFlow x, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sourceAp, sink, sinkAp, c) and + x.callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " [" + sourceAp + "] -> " + sink + " [" + sinkAp + "]" + | + sourceAp.length() > 0 + or + sinkAp.length() > 0 + ) +} + +query predicate clearsContent(string callable, CallableFlowSource source, string content) { + exists(LibraryTypeDataFlow x, Callable callable0, DataFlow::Content content0 | + x.clearsContent(source, content0, callable0) and + callable = callable0.getQualifiedNameWithTypes() and + content = content0.toString() ) } diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected new file mode 100644 index 00000000000..6e924a05cc2 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected @@ -0,0 +1 @@ +| LibraryTypeDataFlow.cs:95:23:95:29 | AString | diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql new file mode 100644 index 00000000000..a2460ac9b19 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql @@ -0,0 +1,5 @@ +import csharp + +from TaintTracking::TaintedMember m +where m.fromSource() +select m diff --git a/csharp/ql/test/library-tests/dataflow/local/Common.qll b/csharp/ql/test/library-tests/dataflow/local/Common.qll index 5c65005407d..4a5be2f007e 100644 --- a/csharp/ql/test/library-tests/dataflow/local/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/local/Common.qll @@ -13,9 +13,9 @@ class MyFlowSource extends DataFlow::Node { or this.asParameter().hasName("tainted") or - exists(Expr e | this = TImplicitDelegateOutNode(e.getAControlFlowNode(), _) | - e.(DelegateCreation).getArgument().(MethodAccess).getTarget().hasName("TaintedMethod") or - e.(LambdaExpr).getExpressionBody().(StringLiteral).getValue() = "taint source" + exists(MyFlowSource mid, DataFlow::ExprNode e | + TaintTracking::localTaintStep+(mid, e) and + e.getExpr() = this.asExpr().(ArrayCreation).getInitializer().getAnElement() ) } } diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index e9a03e58b0a..005d84b1c97 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,12 +1,10 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index f641a355f83..26fc8fffd3a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -24,415 +20,395 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | @@ -785,8 +761,12 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index eea36528104..a5a1e34178f 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Runtime.Serialization; -using System.Threading.Tasks; using System.Web; using System.Web.UI.WebControls; @@ -46,7 +45,7 @@ namespace System.Runtime.Serialization /// public class LocalDataFlow { - public async void M(bool b) + public void M(bool b) { // Assignment, tainted var sink0 = "taint source"; @@ -128,7 +127,7 @@ public class LocalDataFlow Check(sink49); var sink50 = String.Copy(sink49); Check(sink50); - var sink51 = String.Join(", ", "", sink50, ""); + var sink51 = String.Join(", ", new string[] { "", sink50, "" }); Check(sink51); var sink52 = "".Insert(0, sink51); Check(sink52); @@ -152,7 +151,7 @@ public class LocalDataFlow Check(nonSink0); nonSink0 = String.Copy(nonSink0); Check(nonSink0); - nonSink0 = String.Join(", ", "", nonSink0, ""); + nonSink0 = String.Join(", ", new string[] { "", nonSink0, "" }); Check(nonSink0); nonSink0 = "".Insert(0, nonSink0); Check(nonSink0); @@ -218,13 +217,13 @@ public class LocalDataFlow // Ad hoc tracking (System.String), tainted var sink33 = (string)sink32.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(sink33); - var sink48 = sink33.Normalize().Remove(4, 5).Split(' '); + var sink48 = sink33.Normalize().Remove(4, 5); Check(sink48); // Ad hoc tracking (System.String), not tainted nonSink0 = (string)nonSink0.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(nonSink0); - var nonSink15 = nonSink0.Normalize().Remove(4, 5).Split(' '); + var nonSink15 = nonSink0.Normalize().Remove(4, 5); Check(nonSink15); // Ad hoc tracking (System.Text.StringBuilder), tainted @@ -270,18 +269,6 @@ public class LocalDataFlow nonSink0 = nonTaintedTextBox.Text; Check(nonSink0); - // async await, tainted - var sink67 = Task.Run(() => "taint source"); - Check(sink67); - var sink68 = await sink67; - Check(sink68); - - // async await, not tainted - var nonSink21 = Task.Run(() => ""); - Check(nonSink21); - nonSink0 = await nonSink21; - Check(nonSink0); - // Interpolated string, tainted var sink69 = $"test {sink1}"; Check(sink69); @@ -366,7 +353,7 @@ public class LocalDataFlow using (x1 = x) { } IEnumerable os2; - foreach(var o in os2 = os) { } + foreach (var o in os2 = os) { } } public static implicit operator LocalDataFlow(string[] args) => null; diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index e8a0153dc92..30a274af50d 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,51 +1,49 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 77195b49f3d..fd781d984dd 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -24,622 +20,505 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:65:21:65:25 | "abc" | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:69:29:69:32 | "ok" | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:73:31:73:36 | "test" | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | LocalDataFlow.cs:109:22:109:39 | call to method Parse | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | LocalDataFlow.cs:120:22:120:38 | call to method Parse | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | LocalDataFlow.cs:137:20:137:40 | call to method Parse | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | LocalDataFlow.cs:145:20:145:39 | call to method Parse | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:32 | ... > ... | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:40 | call to method Equals | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:45 | call to method Equals | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:175:32:175:36 | false | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:179:32:179:36 | false | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | LocalDataFlow.cs:185:22:185:38 | call to method ToString | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | LocalDataFlow.cs:189:22:189:33 | access to property Query | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | LocalDataFlow.cs:197:20:197:38 | call to method ToString | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | LocalDataFlow.cs:201:20:201:33 | access to property Query | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | LocalDataFlow.cs:219:30:219:48 | call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | LocalDataFlow.cs:219:30:219:87 | call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | -| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | LocalDataFlow.cs:221:22:221:52 | call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | -| LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | LocalDataFlow.cs:221:22:221:63 | call to method Split | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | LocalDataFlow.cs:225:28:225:48 | call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | LocalDataFlow.cs:225:28:225:87 | call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | -| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | LocalDataFlow.cs:227:25:227:57 | call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | -| LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | LocalDataFlow.cs:227:25:227:68 | call to method Split | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | LocalDataFlow.cs:233:22:233:38 | call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | LocalDataFlow.cs:242:20:242:39 | call to method ToString | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:251:22:251:49 | access to indexer | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | access to property AList | LocalDataFlow.cs:260:20:260:47 | access to indexer | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | -| LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | LocalDataFlow.cs:265:22:265:40 | access to property Text | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | -| LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | LocalDataFlow.cs:270:20:270:41 | access to property Text | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:286:24:286:28 | "test " | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:290:22:290:26 | "test " | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:376:29:376:32 | call to operator implicit conversion | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:64:21:64:25 | "abc" | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:68:29:68:32 | "ok" | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:72:31:72:36 | "test" | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:108:22:108:39 | call to method Parse | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:119:22:119:38 | call to method Parse | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:36:126:37 | "" | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | (...) ... | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:34:130:37 | ", " | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | +| LocalDataFlow.cs:130:55:130:56 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:67:130:68 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:23 | "" | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:136:20:136:40 | call to method Parse | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:144:20:144:39 | call to method Parse | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:34:150:35 | "" | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | (...) ... | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:32:154:35 | ", " | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | +| LocalDataFlow.cs:154:53:154:54 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:67:154:68 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:21 | "" | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:32 | ... > ... | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:40 | call to method Equals | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:45 | call to method Equals | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:174:32:174:36 | false | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:178:32:178:36 | false | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:38 | call to method ToString | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:33 | access to property Query | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:38 | call to method ToString | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:33 | access to property Query | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:48 | call to method Substring | +| LocalDataFlow.cs:218:30:218:48 | call to method Substring | LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | +| LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | LocalDataFlow.cs:218:30:218:87 | call to method Trim | +| LocalDataFlow.cs:218:30:218:87 | call to method Trim | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | call to method Replace | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:218:102:218:104 | "b" | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:117:218:118 | "" | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:39 | call to method Normalize | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:39 | call to method Normalize | LocalDataFlow.cs:220:22:220:52 | call to method Remove | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:48 | call to method Substring | +| LocalDataFlow.cs:224:28:224:48 | call to method Substring | LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | +| LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | LocalDataFlow.cs:224:28:224:87 | call to method Trim | +| LocalDataFlow.cs:224:28:224:87 | call to method Trim | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | call to method Replace | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:224:102:224:104 | "b" | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:117:224:118 | "" | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:44 | call to method Normalize | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:44 | call to method Normalize | LocalDataFlow.cs:226:25:226:57 | call to method Remove | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:38 | call to method ToString | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:234:40:234:41 | "" | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:39 | call to method ToString | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:250:22:250:49 | access to indexer | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | access to property AString | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | access to property AString | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:259:20:259:44 | access to property AList | LocalDataFlow.cs:259:20:259:47 | access to indexer | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | access to property Text | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | access to property Text | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:273:24:273:28 | "test " | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:277:22:277:26 | "test " | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:363:29:363:32 | call to operator implicit conversion | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | @@ -1011,12 +890,16 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | -| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | -| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | +| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.cs b/csharp/ql/test/library-tests/dataflow/types/Types.cs index 92f60ec551e..9cb505004b7 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -128,4 +128,28 @@ class Types } static object Through(object x) => x; + + class FieldA + { + public object Field; + + public virtual void M() { } + + public void CallM() => this.M(); + + static void M1(FieldB b, FieldC c) + { + b.Field = new object(); + b.CallM(); // no flow + c.Field = new object(); + c.CallM(); // flow + } + } + + class FieldB : FieldA { } + + class FieldC : FieldA + { + public override void M() => Sink(this.Field); + } } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 15dd073b91d..43b06fb7cba 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -32,17 +32,24 @@ edges | Types.cs:74:9:74:9 | access to local variable d : D | Types.cs:16:30:16:30 | this : D | | Types.cs:77:22:77:22 | a : C | Types.cs:79:18:79:25 | SSA def(b) : C | | Types.cs:79:18:79:25 | SSA def(b) : C | Types.cs:80:18:80:18 | access to local variable b | -| Types.cs:90:22:90:22 | e : E2 | Types.cs:92:26:92:26 | access to parameter e : E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : E2 | Types.cs:93:13:93:16 | this access [Field] : E2 | -| Types.cs:92:26:92:26 | access to parameter e : E2 | Types.cs:92:13:92:16 | [post] this access [Field] : E2 | -| Types.cs:93:13:93:16 | this access [Field] : E2 | Types.cs:113:34:113:34 | this [Field] : E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:90:22:90:22 | e : E2 | -| Types.cs:113:34:113:34 | this [Field] : E2 | Types.cs:115:22:115:25 | this access [Field] : E2 | -| Types.cs:115:22:115:25 | this access [Field] : E2 | Types.cs:115:22:115:31 | access to field Field | +| Types.cs:90:22:90:22 | e : Types.E.E2 | Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | +| Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | +| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | +| Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | +| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:90:22:90:22 | e : Types.E.E2 | +| Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | +| Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:30:122:30 | access to local variable a : A | -| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:30:123:31 | access to local variable e2 : E2 | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | -| Types.cs:123:30:123:31 | access to local variable e2 : E2 | Types.cs:123:22:123:32 | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | +| Types.cs:138:21:138:25 | this [Field] : Object | Types.cs:138:32:138:35 | this access [Field] : Object | +| Types.cs:138:32:138:35 | this access [Field] : Object | Types.cs:153:30:153:30 | this [Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | Types.cs:145:13:145:13 | access to parameter c [Field] : Object | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | +| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | Types.cs:138:21:138:25 | this [Field] : Object | +| Types.cs:153:30:153:30 | this [Field] : Object | Types.cs:153:42:153:45 | this access [Field] : Object | +| Types.cs:153:42:153:45 | this access [Field] : Object | Types.cs:153:42:153:51 | access to field Field | nodes | Types.cs:7:21:7:25 | this : D | semmle.label | this : D | | Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D | @@ -86,35 +93,44 @@ nodes | Types.cs:77:22:77:22 | a : C | semmle.label | a : C | | Types.cs:79:18:79:25 | SSA def(b) : C | semmle.label | SSA def(b) : C | | Types.cs:80:18:80:18 | access to local variable b | semmle.label | access to local variable b | -| Types.cs:90:22:90:22 | e : E2 | semmle.label | e : E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : E2 | semmle.label | [post] this access [Field] : E2 | -| Types.cs:92:26:92:26 | access to parameter e : E2 | semmle.label | access to parameter e : E2 | -| Types.cs:93:13:93:16 | this access [Field] : E2 | semmle.label | this access [Field] : E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | semmle.label | object creation of type E2 : E2 | -| Types.cs:113:34:113:34 | this [Field] : E2 | semmle.label | this [Field] : E2 | -| Types.cs:115:22:115:25 | this access [Field] : E2 | semmle.label | this access [Field] : E2 | +| Types.cs:90:22:90:22 | e : Types.E.E2 | semmle.label | e : Types.E.E2 | +| Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | semmle.label | [post] this access [Field] : Types.E.E2 | +| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | semmle.label | access to parameter e : Types.E.E2 | +| Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | semmle.label | this access [Field] : Types.E.E2 | +| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | +| Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | semmle.label | this [Field] : Types.E.E2 | +| Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | semmle.label | this access [Field] : Types.E.E2 | | Types.cs:115:22:115:31 | access to field Field | semmle.label | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | semmle.label | object creation of type A : A | -| Types.cs:121:26:121:33 | object creation of type E2 : E2 | semmle.label | object creation of type E2 : E2 | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | | Types.cs:122:22:122:31 | call to method Through | semmle.label | call to method Through | | Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | | Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | -| Types.cs:123:30:123:31 | access to local variable e2 : E2 | semmle.label | access to local variable e2 : E2 | +| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | semmle.label | access to local variable e2 : Types.E.E2 | +| Types.cs:138:21:138:25 | this [Field] : Object | semmle.label | this [Field] : Object | +| Types.cs:138:32:138:35 | this access [Field] : Object | semmle.label | this access [Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | semmle.label | [post] access to parameter c [Field] : Object | +| Types.cs:144:23:144:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | semmle.label | access to parameter c [Field] : Object | +| Types.cs:153:30:153:30 | this [Field] : Object | semmle.label | this [Field] : Object | +| Types.cs:153:42:153:45 | this access [Field] : Object | semmle.label | this access [Field] : Object | +| Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field | #select -| Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | -| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | -| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | -| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | -| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | -| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | -| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | +| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | +| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | +| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | +| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:43:20:43:23 | null : null | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | +| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.ql b/csharp/ql/test/library-tests/dataflow/types/Types.ql index da3d8b63b61..57e42a5352e 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.ql +++ b/csharp/ql/test/library-tests/dataflow/types/Types.ql @@ -23,4 +23,4 @@ class Conf extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf where conf.hasFlowPath(source, sink) -select source, sink, sink, "$@", sink, sink.toString() +select source, source, sink, "$@", sink, sink.toString() diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.expected b/csharp/ql/test/library-tests/dispatch/CallContext.expected new file mode 100644 index 00000000000..988fa363b9b --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.expected @@ -0,0 +1,25 @@ +getADynamicTargetInCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:12:29:12:34 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:17:30:17:35 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +mayBenefitFromCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | +| ViableCallable.cs:12:9:12:28 | call to method M | +| ViableCallable.cs:14:9:14:15 | access to property Prop | +| ViableCallable.cs:14:19:14:25 | access to property Prop | +| ViableCallable.cs:16:9:16:23 | access to indexer | +| ViableCallable.cs:16:27:16:41 | access to indexer | +| ViableCallable.cs:18:9:18:16 | access to event Event | +| ViableCallable.cs:19:9:19:16 | access to event Event | +| ViableCallable.cs:22:9:22:30 | call to method M | +| ViableCallable.cs:24:9:24:15 | access to property Prop | +| ViableCallable.cs:24:19:24:25 | access to property Prop | +| ViableCallable.cs:26:9:26:23 | access to indexer | +| ViableCallable.cs:26:27:26:41 | access to indexer | +| ViableCallable.cs:28:9:28:16 | access to event Event | +| ViableCallable.cs:29:9:29:16 | access to event Event | +| ViableCallable.cs:235:9:235:15 | call to method M | +| ViableCallable.cs:284:9:284:15 | call to method M | +| ViableCallable.cs:287:9:287:20 | call to method M | +| ViableCallable.cs:412:9:412:18 | call to method M | +| ViableCallable.cs:456:9:456:30 | call to method M2 | +| ViableCallable.cs:462:9:462:30 | call to method M2 | diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.ql b/csharp/ql/test/library-tests/dispatch/CallContext.ql new file mode 100644 index 00000000000..c21274b0095 --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.ql @@ -0,0 +1,10 @@ +import csharp +import semmle.code.csharp.dispatch.Dispatch + +query predicate getADynamicTargetInCallContext( + DispatchCall call, Callable callable, DispatchCall ctx +) { + callable = call.getADynamicTargetInCallContext(ctx) +} + +query predicate mayBenefitFromCallContext(DispatchCall call) { call.mayBenefitFromCallContext() } diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index bcc68034b71..7fdd307edc8 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -438,7 +438,7 @@ class C17 : C16 // Viable callables: C16.M1() this.M1(""); - // Viable callables: C16.M2() + // Viable callables: C17.M2() this.M2(() => i); } diff --git a/csharp/ql/test/library-tests/generics/Generics.expected b/csharp/ql/test/library-tests/generics/Generics.expected new file mode 100644 index 00000000000..49fe2914a48 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Generics.expected @@ -0,0 +1,178 @@ +test1 +| generics.cs:7:23:7:40 | GenericDelegate<> | +test2 +| generics.cs:9:18:9:18 | A | +test3 +| generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | +test4 +test5 +test6 +| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | +test7 +| Nesting.cs:1:14:1:18 | A | Nesting.cs:6:18:6:22 | B | +| Nesting.cs:1:14:1:18 | A | generics.cs:22:18:22:21 | B | +| generics.cs:13:18:13:21 | A | Nesting.cs:6:18:6:22 | B | +| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B | +test8 +| generics.cs:22:18:22:21 | B | generics.cs:31:21:31:29 | fooParams | +test9 +| generics.cs:22:18:22:21 | B | generics.cs:35:51:35:53 | set_Name | generics.cs:35:51:35:53 | set_Name | +test10 +| generics.cs:22:18:22:21 | B | generics.cs:37:41:37:47 | myEvent | +test11 +| generics.cs:22:18:22:21 | B | generics.cs:39:37:39:38 | ++ | +test12 +| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | +test13 +| generics.cs:60:18:60:24 | Grid | generics.cs:68:20:68:23 | Item | +| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | +test14 +| generics.cs:60:18:60:24 | Grid<> | generics.cs:68:20:68:23 | Item | +test15 +| generics.cs:7:23:7:40 | GenericDelegate | +test16 +| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | +| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | +| generics.cs:134:11:134:16 | Subtle | generics.cs:141:21:141:22 | fs | +test17 +| generics.cs:134:11:134:16 | Subtle | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | 1 | +| generics.cs:134:11:134:16 | Subtle | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | 2 | +test18 +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | T1 | 1 | 1 | +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | T1 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | Int32 | 1 | 1 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | Int32 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 1 | Int32 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 1 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | String | 1 | 1 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 1 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 1 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | T | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Test | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | String | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | String | 2 | 2 | +test19 +| generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | 1 | +| generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | 1 | +test20 +test21 +| generics.cs:147:14:147:14 | E | generics.cs:145:11:145:18 | Param<> | +test22 +| generics.cs:152:14:152:19 | CM1 | Double | +| generics.cs:152:14:152:19 | CM1 | Int32 | +| generics.cs:153:11:153:16 | CM2 | Double | +| generics.cs:153:11:153:16 | CM2 | Int32 | +| generics.cs:157:23:157:29 | CM3 | Double | +| generics.cs:157:23:157:29 | CM3 | Double | +test23 +| generics.cs:178:11:178:24 | Inheritance<> | generics.cs:173:15:173:26 | Interface | +| generics.cs:178:11:178:24 | Inheritance | generics.cs:173:15:173:26 | Interface | +test24 +| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:29:188:30 | T1 | in | +| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:37:188:38 | T2 | out | +test25 +| generics.cs:157:23:157:29 | CM3 | +test26 +test27 +| Nesting.cs:6:18:6:22 | B | Nesting.cs:6:18:6:22 | B<> | Nesting.cs:6:18:6:22 | B<> | +| Nesting.cs:6:18:6:22 | B | Nesting.cs:6:18:6:22 | B<> | Nesting.cs:6:18:6:22 | B<> | +| Nesting.cs:17:22:17:26 | D | Nesting.cs:17:22:17:26 | D<> | Nesting.cs:17:22:17:26 | D<> | +| Nesting.cs:17:22:17:26 | D | Nesting.cs:17:22:17:26 | D<> | Nesting.cs:17:22:17:26 | D<> | +| generics.cs:51:22:51:29 | Inner | generics.cs:51:22:51:29 | Inner<> | generics.cs:51:22:51:29 | Inner<> | +test28 +| Nesting.cs:4:17:4:23 | MA2 | A<>.MA2(T1, T2) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(int, T2) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(string, T2) | +| Nesting.cs:6:18:6:22 | B<> | A<>.B | +| Nesting.cs:6:18:6:22 | B<> | A.B | +| Nesting.cs:6:18:6:22 | B<> | A.B | +| Nesting.cs:9:21:9:27 | MB2 | A<>.B<>.MB2(T1, T3, T4) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(int, string, T4) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(string, int, T4) | +| Nesting.cs:15:21:15:27 | MC2 | A<>.C.MC2(T1, T5) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(int, T5) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(string, T5) | +| Nesting.cs:17:22:17:26 | D<> | A<>.C.D | +| Nesting.cs:17:22:17:26 | D<> | A.C.D | +| Nesting.cs:17:22:17:26 | D<> | A.C.D | +| Nesting.cs:20:25:20:31 | MD2 | A<>.C.D<>.MD2(T1, T6, T7) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(int, bool, T7) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(string, decimal, T7) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A<>.GenericDelegateInGenericClass(T, U) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A.GenericDelegateInGenericClass(int, U) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A.GenericDelegateInGenericClass(string, U) | +| generics.cs:18:18:18:23 | bar | generics.A<>.bar(X, T) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(X, int) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(X, string) | +| generics.cs:45:14:45:17 | f | generics.B<>.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:51:22:51:29 | Inner<> | generics.Outer<>.Inner | +| generics.cs:51:22:51:29 | Inner<> | generics.Outer.Inner | +| generics.cs:137:21:137:25 | fs | generics.Subtle.fs(int) | +| generics.cs:139:21:139:25 | fs | generics.Subtle.fs(int, int) | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(T) | +| generics.cs:155:15:155:23 | Class<> | generics.ConstructedMethods.Class | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class<>.CM3(T2, T1) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(T2, double) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(T2, int) | +test29 +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(int, string) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(string, int) | +| Nesting.cs:6:18:6:22 | B | A.B | +| Nesting.cs:6:18:6:22 | B | A.B | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(int, string, bool) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(string, int, bool) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(int, bool) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(string, bool) | +| Nesting.cs:17:22:17:26 | D | A.C.D | +| Nesting.cs:17:22:17:26 | D | A.C.D | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(int, bool, string) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(string, decimal, bool) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(Test, int) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(int, string) | +| generics.cs:51:22:51:29 | Inner | generics.Outer.Inner | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(double) | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(int) | +| generics.cs:155:15:155:23 | Class | generics.ConstructedMethods.Class | +| generics.cs:155:15:155:23 | Class | generics.ConstructedMethods.Class | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(double, double) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(double, int) | +test30 +| Nesting.cs:3:17:3:19 | MA1 | A.MA1(int) | +| Nesting.cs:3:17:3:19 | MA1 | A.MA1(string) | +| Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(int, string) | +| Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(string, int) | +| Nesting.cs:12:18:12:18 | C | A.C | +| Nesting.cs:12:18:12:18 | C | A.C | +| Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(int) | +| Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(string) | +| Nesting.cs:19:25:19:27 | MD1 | A.C.D.MD1(int, bool) | +| Nesting.cs:19:25:19:27 | MD1 | A.C.D.MD1(string, decimal) | +| Nesting.cs:24:10:24:18 | Construct | A.Construct() | +| Nesting.cs:24:10:24:18 | Construct | A.Construct() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params Object[]) | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params String[]) | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params X[]) | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:175:14:175:16 | set | generics.Interface.set(T) | +test31 diff --git a/csharp/ql/test/library-tests/generics/Generics.ql b/csharp/ql/test/library-tests/generics/Generics.ql new file mode 100644 index 00000000000..f1203f5afc1 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Generics.ql @@ -0,0 +1,252 @@ +import csharp + +query predicate test1(UnboundGenericDelegateType d) { + d.hasName("GenericDelegate<>") and + d.getTypeParameter(0).hasName("T") and + d.getParameter(0).getType().hasName("T") +} + +query predicate test2(Class c) { + c.hasName("A") and + not c instanceof UnboundGenericClass +} + +query predicate test3(ConstructedClass c, UnboundGenericClass d) { + d.hasName("A<>") and + c.getTypeArgument(0).hasName("X") and + c.getTypeArgument(0) instanceof TypeParameter and + c.getUnboundGeneric() = d +} + +query predicate test4(UnboundGenericClass c, string s) { + c.fromSource() and + not c.getName().matches("%<%>") and + s = "Unbound generic class with inconsistent name" +} + +query predicate test5(ConstructedClass c, string s) { + c.fromSource() and + not c.getName().matches("%<%>") and + s = "Constructed class with inconsistent name" +} + +query predicate test6(ConstructedClass at, UnboundGenericClass b, ConstructedClass bt, Field f) { + at.hasName("A") and + b.hasName("B<>") and + bt.hasName("B") and + at.getTypeArgument(0).hasName("T") and + at.getTypeArgument(0) instanceof TypeParameter and + at.getTypeArgument(0) = b.getTypeParameter(0) and + bt.getUnboundGeneric() = b and + f.getDeclaringType() = b and + f.getType() = at +} + +query predicate test7(ConstructedClass aString, ConstructedClass bString) { + aString.hasName("A") and + bString.hasName("B") and + aString.getSourceDeclaration().hasName("A<>") and + bString.getSourceDeclaration().hasName("B<>") +} + +query predicate test8(ConstructedClass bString, Method m) { + bString.hasName("B") and + m.getDeclaringType() = bString and + m.hasName("fooParams") and + m.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType and + m.getSourceDeclaration().getDeclaringType() = m.getDeclaringType().getSourceDeclaration() +} + +query predicate test9(ConstructedClass bString, Setter sourceSetter, Setter setter) { + exists(Property p | + bString.hasName("B") and + p.getDeclaringType() = bString and + p.hasName("Name") and + p.getSourceDeclaration().getDeclaringType() = p.getDeclaringType().getSourceDeclaration() and + p.getSetter().getParameter(0).getType() instanceof StringType and + p.getSetter().getSourceDeclaration() = p.getSourceDeclaration().getSetter() and + p.getGetter().getSourceDeclaration() = p.getSourceDeclaration().getGetter() and + sourceSetter = p.getSourceDeclaration().getSetter() and + setter = p.getSetter() + ) +} + +query predicate test10(ConstructedClass bString, Event e) { + bString.hasName("B") and + e.getDeclaringType() = bString and + e.hasName("myEvent") and + e.getSourceDeclaration().getDeclaringType() = e.getDeclaringType().getSourceDeclaration() and + e.getType().(ConstructedDelegateType).getTypeArgument(0) instanceof StringType and + e.getAddEventAccessor().getSourceDeclaration() = e.getSourceDeclaration().getAddEventAccessor() and + e.getRemoveEventAccessor().getSourceDeclaration() = + e.getSourceDeclaration().getRemoveEventAccessor() +} + +query predicate test11(ConstructedClass bString, Operator o) { + bString.hasName("B") and + o.getDeclaringType() = bString and + o instanceof IncrementOperator and + o.getSourceDeclaration().getDeclaringType() = o.getDeclaringType().getSourceDeclaration() +} + +query predicate test12(ConstructedClass gridInt, Indexer i) { + gridInt.hasName("Grid") and + i.getDeclaringType() = gridInt and + i.getSourceDeclaration().getDeclaringType() = i.getDeclaringType().getSourceDeclaration() and + i.getGetter().getSourceDeclaration() = i.getSourceDeclaration().getGetter() and + i.getSetter().getSourceDeclaration() = i.getSourceDeclaration().getSetter() +} + +query predicate test13(ConstructedClass gridInt, Indexer i) { + gridInt.hasName("Grid") and + i.getDeclaringType() = gridInt and + i.getType() instanceof IntType +} + +query predicate test14(UnboundGenericClass gridInt, Indexer i) { + gridInt.hasName("Grid<>") and + i.getDeclaringType() = gridInt and + i.getType() instanceof IntType +} + +query predicate test15(ConstructedDelegateType d) { + d.hasName("GenericDelegate") and + d.getTypeArgument(0) instanceof StringType and + d.getParameter(0).getType() instanceof StringType +} + +query predicate test16(Class c, Method m) { + c.hasName("Subtle") and + count(c.getAMethod()) = 3 and + m = c.getAMethod() +} + +query predicate test17( + Class c, TypeParameter p, UnboundGenericMethod m, TypeParameter q, UnboundGenericMethod n, + int numParams +) { + c.hasName("Subtle") and + m = c.getAMethod() and + m.getATypeParameter() = p and + n = c.getAMethod() and + n.getATypeParameter() = q and + m != n and + p != q and + numParams = m.getNumberOfParameters() +} + +query predicate test18( + Class c, Method m, Parameter p, int numArgs, string typeName, int numParams, int numTypes +) { + c.getName().matches("A<%") and + m = c.getAMethod() and + p = m.getAParameter() and + numArgs = count(m.(ConstructedMethod).getATypeArgument()) and + typeName = p.getType().getName() and + numParams = count(m.getAParameter()) and + numTypes = count(m.getAParameter().getType()) +} + +/** Test that locations are populated for the type parameters of generic methods. */ +query predicate test19(UnboundGenericMethod m, TypeParameter tp, int hasLoc) { + m.hasName("fs") and + tp = m.getATypeParameter() and + if exists(tp.getLocation()) then hasLoc = 1 else hasLoc = 0 +} + +/** Test that locations are populated for unbound generic types. */ +query predicate test20(UnboundGenericType t, string s) { + not type_location(t, _) and s = "Missing location" +} + +/** + * This tests a regression in the extractor where the following failed to extract: + * + * class Foo + * { + * enum E { a }; + * } + */ +query predicate test21(Enum e, Class c) { + c.hasName("Param<>") and + e.hasName("E") and + e.getDeclaringType() = c +} + +query predicate test22(ConstructedMethod m, string tpName) { + m.getName().matches("CM%") and + tpName = m.getATypeArgument().getName() +} + +query predicate test23(Class c, Interface i) { + c.getName().matches("Inheritance%") and + i = c.getABaseInterface() +} + +query predicate test24(UnboundGenericInterface ugi, TypeParameter tp, string s) { + ugi.fromSource() and + ugi.getATypeParameter() = tp and + ( + tp.isOut() and s = "out" + or + tp.isIn() and s = "in" + ) +} + +query predicate test25(ConstructedMethod cm) { + cm.hasName("CM3") and + cm.getParameter(0).getType() instanceof DoubleType and + cm.getParameter(1).getType() instanceof IntType and + cm.getReturnType() instanceof DoubleType and + exists(Method sourceDeclaration | + sourceDeclaration = cm.getSourceDeclaration() and + sourceDeclaration.getParameter(0).getType().(TypeParameter).hasName("T2") and + sourceDeclaration.getParameter(1).getType().(TypeParameter).hasName("T1") and + sourceDeclaration.getReturnType().(TypeParameter).hasName("T2") + ) and + exists(Method unbound | + unbound = cm.getUnboundGeneric() and + unbound.getParameter(0).getType().(TypeParameter).hasName("T2") and + unbound.getParameter(1).getType() instanceof IntType and + unbound.getReturnType().(TypeParameter).hasName("T2") + ) +} + +query predicate test26(ConstructedGeneric cg, string s) { + // Source declaration and unbound generic must be unique + ( + strictcount(cg.getSourceDeclaration+()) > 1 or + strictcount(cg.getUnboundGeneric()) > 1 + ) and + s = "Non-unique source decl or unbound generic" +} + +query predicate test27(ConstructedType ct, UnboundGenericType ugt, UnboundGenericType sourceDecl) { + ct instanceof NestedType and + ugt = ct.getUnboundGeneric() and + sourceDecl = ct.getSourceDeclaration() and + ugt != sourceDecl +} + +query predicate test28(UnboundGeneric ug, string s) { + ug.fromSource() and + s = ug.getQualifiedNameWithTypes() +} + +query predicate test29(ConstructedGeneric cg, string s) { + cg.fromSource() and + s = cg.getQualifiedNameWithTypes() +} + +query predicate test30(Declaration d, string s) { + d.fromSource() and + d instanceof @generic and + s = d.getQualifiedNameWithTypes() and + d != d.getSourceDeclaration() and + not d instanceof Generic +} + +query predicate test31(ConstructedGeneric cg, string s) { + not exists(cg.getUnboundGeneric()) and + s = "Missing unbound generic" +} diff --git a/csharp/ql/test/library-tests/generics/Generics1.expected b/csharp/ql/test/library-tests/generics/Generics1.expected deleted file mode 100644 index 4844661e17a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics1.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:7:23:7:40 | GenericDelegate<> | diff --git a/csharp/ql/test/library-tests/generics/Generics1.ql b/csharp/ql/test/library-tests/generics/Generics1.ql deleted file mode 100644 index 5ca34d50270..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics1.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from UnboundGenericDelegateType d -where - d.hasName("GenericDelegate<>") and - d.getTypeParameter(0).hasName("T") and - d.getParameter(0).getType().hasName("T") -select d diff --git a/csharp/ql/test/library-tests/generics/Generics10.expected b/csharp/ql/test/library-tests/generics/Generics10.expected deleted file mode 100644 index c6031e740ff..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics10.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:37:41:37:47 | myEvent | diff --git a/csharp/ql/test/library-tests/generics/Generics10.ql b/csharp/ql/test/library-tests/generics/Generics10.ql deleted file mode 100644 index 276130ae662..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics10.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Event e -where - bString.hasName("B") and - e.getDeclaringType() = bString and - e.hasName("myEvent") and - e.getSourceDeclaration().getDeclaringType() = e.getDeclaringType().getSourceDeclaration() and - e.getType().(ConstructedDelegateType).getTypeArgument(0) instanceof StringType and - e.getAddEventAccessor().getSourceDeclaration() = e.getSourceDeclaration().getAddEventAccessor() and - e.getRemoveEventAccessor().getSourceDeclaration() = - e.getSourceDeclaration().getRemoveEventAccessor() -select bString, e diff --git a/csharp/ql/test/library-tests/generics/Generics11.expected b/csharp/ql/test/library-tests/generics/Generics11.expected deleted file mode 100644 index 5582726e81c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics11.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:39:37:39:38 | ++ | diff --git a/csharp/ql/test/library-tests/generics/Generics11.ql b/csharp/ql/test/library-tests/generics/Generics11.ql deleted file mode 100644 index 18625758c3e..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics11.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Operator o -where - bString.hasName("B") and - o.getDeclaringType() = bString and - o instanceof IncrementOperator and - o.getSourceDeclaration().getDeclaringType() = o.getDeclaringType().getSourceDeclaration() -select bString, o diff --git a/csharp/ql/test/library-tests/generics/Generics12.expected b/csharp/ql/test/library-tests/generics/Generics12.expected deleted file mode 100644 index fd91ce5b6f7..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics12.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics12.ql b/csharp/ql/test/library-tests/generics/Generics12.ql deleted file mode 100644 index c54f41c12e2..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics12.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass gridInt, Indexer i -where - gridInt.hasName("Grid") and - i.getDeclaringType() = gridInt and - i.getSourceDeclaration().getDeclaringType() = i.getDeclaringType().getSourceDeclaration() and - i.getGetter().getSourceDeclaration() = i.getSourceDeclaration().getGetter() and - i.getSetter().getSourceDeclaration() = i.getSourceDeclaration().getSetter() -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics13.expected b/csharp/ql/test/library-tests/generics/Generics13.expected deleted file mode 100644 index dcbf45ddb6f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics13.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:60:18:60:24 | Grid | generics.cs:68:20:68:23 | Item | -| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics13.ql b/csharp/ql/test/library-tests/generics/Generics13.ql deleted file mode 100644 index 338421c7d84..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics13.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass gridInt, Indexer i -where - gridInt.hasName("Grid") and - i.getDeclaringType() = gridInt and - i.getType() instanceof IntType -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics14.expected b/csharp/ql/test/library-tests/generics/Generics14.expected deleted file mode 100644 index b706be3b95f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics14.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:60:18:60:24 | Grid<> | generics.cs:68:20:68:23 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics14.ql b/csharp/ql/test/library-tests/generics/Generics14.ql deleted file mode 100644 index 312e93649c2..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics14.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from UnboundGenericClass gridInt, Indexer i -where - gridInt.hasName("Grid<>") and - i.getDeclaringType() = gridInt and - i.getType() instanceof IntType -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics15.expected b/csharp/ql/test/library-tests/generics/Generics15.expected deleted file mode 100644 index b160a14cb5f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics15.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:7:23:7:40 | GenericDelegate | diff --git a/csharp/ql/test/library-tests/generics/Generics15.ql b/csharp/ql/test/library-tests/generics/Generics15.ql deleted file mode 100644 index 0fbaeaa4caa..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics15.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedDelegateType d -where - d.hasName("GenericDelegate") and - d.getTypeArgument(0) instanceof StringType and - d.getParameter(0).getType() instanceof StringType -select d diff --git a/csharp/ql/test/library-tests/generics/Generics16.expected b/csharp/ql/test/library-tests/generics/Generics16.expected deleted file mode 100644 index 501e3de64fe..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics16.expected +++ /dev/null @@ -1,3 +0,0 @@ -| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | -| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | -| generics.cs:134:11:134:16 | Subtle | generics.cs:141:21:141:22 | fs | diff --git a/csharp/ql/test/library-tests/generics/Generics16.ql b/csharp/ql/test/library-tests/generics/Generics16.ql deleted file mode 100644 index 26930274ab8..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics16.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c -where - c.hasName("Subtle") and - count(c.getAMethod()) = 3 -select c, c.getAMethod() diff --git a/csharp/ql/test/library-tests/generics/Generics17.expected b/csharp/ql/test/library-tests/generics/Generics17.expected deleted file mode 100644 index 5c5315b45ac..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics17.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | 1 | generics.cs:137:24:137:24 | X | generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | -| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | 2 | generics.cs:139:24:139:24 | X | generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | diff --git a/csharp/ql/test/library-tests/generics/Generics17.ql b/csharp/ql/test/library-tests/generics/Generics17.ql deleted file mode 100644 index d09d726b41d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics17.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c, TypeParameter p, UnboundGenericMethod m, TypeParameter q, UnboundGenericMethod n -where - c.hasName("Subtle") and - m = c.getAMethod() and - m.getATypeParameter() = p and - n = c.getAMethod() and - n.getATypeParameter() = q and - m != n and - p != q -select c, m, m.getNumberOfParameters(), p, n, q diff --git a/csharp/ql/test/library-tests/generics/Generics18.expected b/csharp/ql/test/library-tests/generics/Generics18.expected deleted file mode 100644 index 2fac79fddb6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics18.expected +++ /dev/null @@ -1,10 +0,0 @@ -| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | T | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Test | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | String | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | String | 2 | 2 | diff --git a/csharp/ql/test/library-tests/generics/Generics18.ql b/csharp/ql/test/library-tests/generics/Generics18.ql deleted file mode 100644 index d024bbfc8c3..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics18.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generic parameter types - */ - -import csharp - -from Class c, Method m -where - c.getName().matches("A<%") and - m = c.getAMethod() -select c, m, m.getAParameter() as p, count(m.(ConstructedMethod).getATypeArgument()), - p.getType().getName(), count(m.getAParameter()), count(m.getAParameter().getType()) diff --git a/csharp/ql/test/library-tests/generics/Generics19.expected b/csharp/ql/test/library-tests/generics/Generics19.expected deleted file mode 100644 index 63dd29a1ef6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics19.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | 1 | -| generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics19.ql b/csharp/ql/test/library-tests/generics/Generics19.ql deleted file mode 100644 index f946bc75c0a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics19.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test that locations are populated for the type parameters of generic methods - */ - -import csharp - -from UnboundGenericMethod m, TypeParameter tp, int hasLoc -where - m.hasName("fs") and - tp = m.getATypeParameter() and - if exists(tp.getLocation()) then hasLoc = 1 else hasLoc = 0 -select m, tp, hasLoc diff --git a/csharp/ql/test/library-tests/generics/Generics2.expected b/csharp/ql/test/library-tests/generics/Generics2.expected deleted file mode 100644 index 93dc2c1a9fa..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics2.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:9:18:9:18 | A | diff --git a/csharp/ql/test/library-tests/generics/Generics2.ql b/csharp/ql/test/library-tests/generics/Generics2.ql deleted file mode 100644 index dc0346ce630..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics2.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c -where - c.hasName("A") and - not c instanceof UnboundGenericClass -select c diff --git a/csharp/ql/test/library-tests/generics/Generics20.expected b/csharp/ql/test/library-tests/generics/Generics20.expected deleted file mode 100755 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics20.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics20.ql b/csharp/ql/test/library-tests/generics/Generics20.ql deleted file mode 100644 index f5da66d4c66..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics20.ql +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @name Test that locations are populated for unbound generic types - */ - -import csharp - -from UnboundGenericType t -where type_location(t, _) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics21.expected b/csharp/ql/test/library-tests/generics/Generics21.expected deleted file mode 100644 index b3a788aad22..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics21.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:145:11:145:18 | Param<> | generics.cs:147:14:147:14 | E | diff --git a/csharp/ql/test/library-tests/generics/Generics21.ql b/csharp/ql/test/library-tests/generics/Generics21.ql deleted file mode 100644 index f3273b0384f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics21.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp - -/* - * This tests a regression in the extractor where the following failed to extract: - * - * class Foo - * { - * enum E { a }; - * } - */ - -from Enum e, Class c -where - c.hasName("Param<>") and - e.hasName("E") and - e.getDeclaringType() = c -select c, e diff --git a/csharp/ql/test/library-tests/generics/Generics22.expected b/csharp/ql/test/library-tests/generics/Generics22.expected deleted file mode 100644 index 2575df885ba..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics22.expected +++ /dev/null @@ -1,6 +0,0 @@ -| generics.cs:152:14:152:19 | CM1 | Double | -| generics.cs:152:14:152:19 | CM1 | Int32 | -| generics.cs:153:11:153:16 | CM2 | Double | -| generics.cs:153:11:153:16 | CM2 | Int32 | -| generics.cs:157:23:157:29 | CM3 | Double | -| generics.cs:157:23:157:29 | CM3 | Double | diff --git a/csharp/ql/test/library-tests/generics/Generics22.ql b/csharp/ql/test/library-tests/generics/Generics22.ql deleted file mode 100644 index 313317b7c3c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics22.ql +++ /dev/null @@ -1,7 +0,0 @@ -import csharp - -from ConstructedMethod m, ValueOrRefType tp -where - m.getName().matches("CM%") and - tp = m.getATypeArgument() -select m, tp.getName() diff --git a/csharp/ql/test/library-tests/generics/Generics23.expected b/csharp/ql/test/library-tests/generics/Generics23.expected deleted file mode 100644 index 89cd51b4ecc..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics23.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:178:11:178:24 | Inheritance<> | generics.cs:173:15:173:26 | Interface | -| generics.cs:178:11:178:24 | Inheritance | generics.cs:173:15:173:26 | Interface | diff --git a/csharp/ql/test/library-tests/generics/Generics23.ql b/csharp/ql/test/library-tests/generics/Generics23.ql deleted file mode 100644 index 2fde708af4d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics23.ql +++ /dev/null @@ -1,7 +0,0 @@ -import csharp - -from Class c, Interface i -where - c.getName().matches("Inheritance%") and - i = c.getABaseInterface() -select c, i diff --git a/csharp/ql/test/library-tests/generics/Generics24.expected b/csharp/ql/test/library-tests/generics/Generics24.expected deleted file mode 100644 index b2215d70775..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics24.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:29:188:30 | T1 | in | -| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:37:188:38 | T2 | out | diff --git a/csharp/ql/test/library-tests/generics/Generics24.ql b/csharp/ql/test/library-tests/generics/Generics24.ql deleted file mode 100644 index 33ca571722b..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics24.ql +++ /dev/null @@ -1,12 +0,0 @@ -import csharp - -from UnboundGenericInterface ugi, TypeParameter tp, string s -where - ugi.fromSource() and - ugi.getATypeParameter() = tp and - ( - tp.isOut() and s = "out" - or - tp.isIn() and s = "in" - ) -select ugi, tp, s diff --git a/csharp/ql/test/library-tests/generics/Generics25.expected b/csharp/ql/test/library-tests/generics/Generics25.expected deleted file mode 100644 index 8be7c243e47..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics25.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:157:23:157:29 | CM3 | diff --git a/csharp/ql/test/library-tests/generics/Generics25.ql b/csharp/ql/test/library-tests/generics/Generics25.ql deleted file mode 100644 index 46743cdf467..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics25.ql +++ /dev/null @@ -1,21 +0,0 @@ -import csharp - -from ConstructedMethod cm -where - cm.hasName("CM3") and - cm.getParameter(0).getType() instanceof DoubleType and - cm.getParameter(1).getType() instanceof IntType and - cm.getReturnType() instanceof DoubleType and - exists(Method sourceDeclaration | - sourceDeclaration = cm.getSourceDeclaration() and - sourceDeclaration.getParameter(0).getType().(TypeParameter).hasName("T2") and - sourceDeclaration.getParameter(1).getType().(TypeParameter).hasName("T1") and - sourceDeclaration.getReturnType().(TypeParameter).hasName("T2") - ) and - exists(Method unbound | - unbound = cm.getUnboundGeneric() and - unbound.getParameter(0).getType().(TypeParameter).hasName("T2") and - unbound.getParameter(1).getType() instanceof IntType and - unbound.getReturnType().(TypeParameter).hasName("T2") - ) -select cm diff --git a/csharp/ql/test/library-tests/generics/Generics26.expected b/csharp/ql/test/library-tests/generics/Generics26.expected deleted file mode 100644 index 4b08b24ae8c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics26.expected +++ /dev/null @@ -1 +0,0 @@ -| Test passed | diff --git a/csharp/ql/test/library-tests/generics/Generics26.ql b/csharp/ql/test/library-tests/generics/Generics26.ql deleted file mode 100644 index bb1ae00efac..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics26.ql +++ /dev/null @@ -1,9 +0,0 @@ -import csharp - -// Source declaration and unbound generic must be unique -where - not exists(ConstructedGeneric cg | - strictcount(cg.getSourceDeclaration+()) > 1 or - strictcount(cg.getUnboundGeneric()) > 1 - ) -select "Test passed" diff --git a/csharp/ql/test/library-tests/generics/Generics27.expected b/csharp/ql/test/library-tests/generics/Generics27.expected deleted file mode 100644 index 8a3d5ff770a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics27.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:51:22:51:29 | Inner | generics.cs:51:22:51:29 | Inner<> | generics.cs:51:22:51:29 | Inner<> | diff --git a/csharp/ql/test/library-tests/generics/Generics27.ql b/csharp/ql/test/library-tests/generics/Generics27.ql deleted file mode 100644 index c07497a2aab..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics27.ql +++ /dev/null @@ -1,9 +0,0 @@ -import csharp - -from ConstructedType ct, UnboundGenericType ugt, UnboundGenericType sourceDecl -where - ct instanceof NestedType and - ugt = ct.getUnboundGeneric() and - sourceDecl = ct.getSourceDeclaration() and - ugt != sourceDecl -select ct, ugt, sourceDecl diff --git a/csharp/ql/test/library-tests/generics/Generics3.expected b/csharp/ql/test/library-tests/generics/Generics3.expected deleted file mode 100644 index 3ccef83782a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics3.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | diff --git a/csharp/ql/test/library-tests/generics/Generics3.ql b/csharp/ql/test/library-tests/generics/Generics3.ql deleted file mode 100644 index 2b9da24a8e6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics3.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass c, UnboundGenericClass d -where - c.hasName("A") and - d.hasName("A<>") and - c.getTypeArgument(0).hasName("X") and - c.getTypeArgument(0) instanceof TypeParameter and - c.getUnboundGeneric() = d -select c, d diff --git a/csharp/ql/test/library-tests/generics/Generics4.expected b/csharp/ql/test/library-tests/generics/Generics4.expected deleted file mode 100644 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics4.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics4.ql b/csharp/ql/test/library-tests/generics/Generics4.ql deleted file mode 100644 index fb627b8ef95..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics4.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -where forex(UnboundGenericClass c | c.fromSource() | c.getName().matches("%<%>")) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics5.expected b/csharp/ql/test/library-tests/generics/Generics5.expected deleted file mode 100644 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics5.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics5.ql b/csharp/ql/test/library-tests/generics/Generics5.ql deleted file mode 100644 index c694ecb576c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics5.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -where forex(ConstructedClass c | c.getName().matches("%<%>")) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics6.expected b/csharp/ql/test/library-tests/generics/Generics6.expected deleted file mode 100644 index c8baae12f6e..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics6.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | generics.cs:13:18:13:21 | A | diff --git a/csharp/ql/test/library-tests/generics/Generics6.ql b/csharp/ql/test/library-tests/generics/Generics6.ql deleted file mode 100644 index c3a3ab4786d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics6.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass at, UnboundGenericClass b, ConstructedClass bt, Field f -where - at.hasName("A") and - b.hasName("B<>") and - bt.hasName("B") and - at.getTypeArgument(0).hasName("T") and - at.getTypeArgument(0) instanceof TypeParameter and - at.getTypeArgument(0) = b.getTypeParameter(0) and - bt.getUnboundGeneric() = b and - f.getDeclaringType() = b and - f.getType() = at -select b, bt, f, at diff --git a/csharp/ql/test/library-tests/generics/Generics7.expected b/csharp/ql/test/library-tests/generics/Generics7.expected deleted file mode 100644 index 05be9f71e69..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics7.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B | diff --git a/csharp/ql/test/library-tests/generics/Generics7.ql b/csharp/ql/test/library-tests/generics/Generics7.ql deleted file mode 100644 index 60ac39bbc77..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics7.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass aString, ConstructedClass bString -where - aString.hasName("A") and - bString.hasName("B") and - aString.getSourceDeclaration().hasName("A<>") and - bString.getSourceDeclaration().hasName("B<>") -select aString, bString diff --git a/csharp/ql/test/library-tests/generics/Generics8.expected b/csharp/ql/test/library-tests/generics/Generics8.expected deleted file mode 100644 index 60bb21919e4..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics8.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:31:21:31:29 | fooParams | diff --git a/csharp/ql/test/library-tests/generics/Generics8.ql b/csharp/ql/test/library-tests/generics/Generics8.ql deleted file mode 100644 index 7bcba49bb11..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics8.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Method m -where - bString.hasName("B") and - m.getDeclaringType() = bString and - m.hasName("fooParams") and - m.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType and - m.getSourceDeclaration().getDeclaringType() = m.getDeclaringType().getSourceDeclaration() -select bString, m diff --git a/csharp/ql/test/library-tests/generics/Generics9.expected b/csharp/ql/test/library-tests/generics/Generics9.expected deleted file mode 100644 index afbfb6110d1..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics9.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:35:51:35:53 | set_Name | generics.cs:35:51:35:53 | set_Name | diff --git a/csharp/ql/test/library-tests/generics/Generics9.ql b/csharp/ql/test/library-tests/generics/Generics9.ql deleted file mode 100644 index 88d7404a72c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics9.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Property p -where - bString.hasName("B") and - p.getDeclaringType() = bString and - p.hasName("Name") and - p.getSourceDeclaration().getDeclaringType() = p.getDeclaringType().getSourceDeclaration() and - p.getSetter().getParameter(0).getType() instanceof StringType and - p.getSetter().getSourceDeclaration() = p.getSourceDeclaration().getSetter() and - p.getGetter().getSourceDeclaration() = p.getSourceDeclaration().getGetter() -select bString, p.getSourceDeclaration().getSetter(), p.getSetter() diff --git a/csharp/ql/test/library-tests/generics/Nesting.cs b/csharp/ql/test/library-tests/generics/Nesting.cs new file mode 100644 index 00000000000..e176f055497 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Nesting.cs @@ -0,0 +1,58 @@ +public class A +{ + public void MA1(T1 x) { } + public void MA2(T1 x, T2 y) { } + + public class B + { + public void MB1(T1 x, T3 y) { } + public void MB2(T1 x, T3 y, T4 z) { } + } + + public class C + { + public void MC1(T1 x) { } + public void MC2(T1 x, T5 y) { } + + public class D + { + public void MD1(T1 x, T6 y) { } + public void MD2(T1 x, T6 y, T7 z) { } + } + } + + void Construct() + { + var a1 = new A(); + a1.MA1(0); + a1.MA2(0, ""); + + var a2 = new A(); + a2.MA1(""); + a2.MA2("", 0); + + var b1 = new A.B(); + b1.MB1(0, ""); + b1.MB2(0, "", false); + + var b2 = new A.B(); + b2.MB1("", 0); + b2.MB2("", 0, false); + + var c1 = new A.C(); + c1.MC1(0); + c1.MC2(0, false); + + var c2 = new A.C(); + c2.MC1(""); + c2.MC2("", false); + + var d1 = new A.C.D(); + d1.MD1(0, false); + d1.MD2(0, false, ""); + + var d2 = new A.C.D(); + d2.MD1("", 0m); + d2.MD2("", 0m, false); + } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref deleted file mode 100644 index 1f503d46e01..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref deleted file mode 100644 index f51fa9def9b..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected deleted file mode 100644 index 61bc9b2261c..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ /dev/null @@ -1,26 +0,0 @@ -missingOperand -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -missingIRType -multipleIRTypes diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref deleted file mode 100644 index 4ee5a4fdd33..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected deleted file mode 100644 index 7c2d1faf639..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref deleted file mode 100644 index 1b7d4a7996a..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/overrides/Implements.expected b/csharp/ql/test/library-tests/overrides/Implements.expected index 8af3fb97b8e..e86cd58b4fd 100644 --- a/csharp/ql/test/library-tests/overrides/Implements.expected +++ b/csharp/ql/test/library-tests/overrides/Implements.expected @@ -27,3 +27,4 @@ | overrides.cs:268:29:268:36 | Property | overrides.cs:216:13:216:20 | Property | | overrides.cs:269:29:269:32 | Item | overrides.cs:217:13:217:16 | Item | | overrides.cs:270:44:270:48 | Event | overrides.cs:218:28:218:32 | Event | +| overrides.cs:284:25:284:28 | M | overrides.cs:279:18:279:21 | M | diff --git a/csharp/ql/test/library-tests/overrides/Overrides19.expected b/csharp/ql/test/library-tests/overrides/Overrides19.expected index 4b490b1f27d..962c6171c85 100644 --- a/csharp/ql/test/library-tests/overrides/Overrides19.expected +++ b/csharp/ql/test/library-tests/overrides/Overrides19.expected @@ -9,3 +9,4 @@ | overrides.cs:249:22:249:25 | M | overrides.cs:247:11:247:12 | A6 | overrides.cs:162:11:162:14 | M | overrides.cs:160:22:160:26 | I2 | | overrides.cs:259:27:259:30 | M | overrides.cs:257:11:257:12 | A8 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 | | overrides.cs:267:27:267:30 | M | overrides.cs:265:11:265:12 | A9 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 | +| overrides.cs:284:25:284:28 | M | overrides.cs:282:15:282:17 | A10 | overrides.cs:279:18:279:21 | M | overrides.cs:277:19:277:20 | I6 | diff --git a/csharp/ql/test/library-tests/overrides/Overrides22.expected b/csharp/ql/test/library-tests/overrides/Overrides22.expected index 11bb9d46cbd..1322e0c3ccf 100644 --- a/csharp/ql/test/library-tests/overrides/Overrides22.expected +++ b/csharp/ql/test/library-tests/overrides/Overrides22.expected @@ -47,3 +47,4 @@ | overrides.G2.M(string, S) | overrides.G.M(string, S) | overrides | | overrides.G.M(string, S) | overrides.I2.M(string, S) | implements | | overrides.H<>.M(TA, S) | overrides.I2.M(TA, S) | implements | +| overrides.Outer<>.A10.M(Inner) | overrides.Outer<>.I6.M(Inner) | implements | diff --git a/csharp/ql/test/library-tests/overrides/overrides.cs b/csharp/ql/test/library-tests/overrides/overrides.cs index 9430db3f9c0..bb9520a7a54 100644 --- a/csharp/ql/test/library-tests/overrides/overrides.cs +++ b/csharp/ql/test/library-tests/overrides/overrides.cs @@ -269,6 +269,23 @@ namespace overrides public override int this[int x] { get { return x; } } // overrides A2.Item public override event EventHandler Event; // overrides A2.Event } + + class Outer + { + class Inner { } + + interface I6 + { + void M(Outer.Inner x); + } + + class A10 + { + public void M(Outer.Inner x) { } // implements I6.M (via A11) + } + + class A11 : A10, I6 { } + } } // semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll diff --git a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected index a9eb533c152..0e09204b40e 100644 --- a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected +++ b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected @@ -17,13 +17,11 @@ | ControlFlow.cs:10:22:10:26 | access to property (unknown) | ControlFlow.cs:10:29:10:42 | "This is true" | | ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | Call (unknown target) | | ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | call to method | -| ControlFlow.cs:12:9:12:86 | Call (unknown target) | ControlFlow.cs:12:37:12:47 | Expression | +| ControlFlow.cs:12:9:12:86 | Call (unknown target) | ControlFlow.cs:12:51:12:62 | access to field Empty | | ControlFlow.cs:12:9:12:87 | ...; | ControlFlow.cs:12:9:12:86 | Call (unknown target) | | ControlFlow.cs:12:35:12:86 | { ..., ... } | ControlFlow.cs:7:10:7:10 | exit F | -| ControlFlow.cs:12:37:12:47 | Expression | ControlFlow.cs:12:51:12:62 | access to field Empty | -| ControlFlow.cs:12:37:12:62 | ... = ... | ControlFlow.cs:12:65:12:75 | Expression | +| ControlFlow.cs:12:37:12:62 | ... = ... | ControlFlow.cs:12:79:12:79 | access to local variable v | | ControlFlow.cs:12:51:12:62 | access to field Empty | ControlFlow.cs:12:37:12:62 | ... = ... | -| ControlFlow.cs:12:65:12:75 | Expression | ControlFlow.cs:12:79:12:79 | access to local variable v | | ControlFlow.cs:12:65:12:84 | ... = ... | ControlFlow.cs:12:35:12:86 | { ..., ... } | | ControlFlow.cs:12:79:12:79 | access to local variable v | ControlFlow.cs:12:79:12:84 | Call (unknown target) | | ControlFlow.cs:12:79:12:79 | access to local variable v | ControlFlow.cs:12:79:12:84 | access to property (unknown) | diff --git a/csharp/ql/test/library-tests/unification/Unification.cs b/csharp/ql/test/library-tests/unification/Unification.cs index 38c069599d4..e392911030c 100644 --- a/csharp/ql/test/library-tests/unification/Unification.cs +++ b/csharp/ql/test/library-tests/unification/Unification.cs @@ -1,6 +1,7 @@ interface I1 { } -struct S1 { } struct S2 { } +struct S1 { } +struct S2 { } class C0 { } class C1 { } @@ -31,3 +32,19 @@ class Tuples static (T8, T9) t4; static (T8 a, T9 b) t5 = t4; } + +class Nested +{ + class NestedA { } + class NestedB + { + public class NestedC { } + } + + Nested.NestedA x1; + Nested.NestedA x2; + Nested.NestedB x3; + Nested.NestedB x4; + Nested.NestedB.NestedC x5; + Nested.NestedB.NestedC x6; +} diff --git a/csharp/ql/test/library-tests/unification/Unification.expected b/csharp/ql/test/library-tests/unification/Unification.expected index 6c173661a19..b423003be37 100644 --- a/csharp/ql/test/library-tests/unification/Unification.expected +++ b/csharp/ql/test/library-tests/unification/Unification.expected @@ -1,298 +1,378 @@ constrainedTypeParameterSubsumes -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:1:11:1:12 | I1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:6:7:6:8 | C0 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:10:9:11 | T3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:14:7:14:24 | ConstructSomeTypes | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:24:12:24:13 | Tm | constrainedTypeParameterSubsumptionImpliesUnification constrainedTypeParameterUnifiable -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:1:11:1:12 | I1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:6:7:6:8 | C0 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:10:9:11 | T3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:14:7:14:24 | ConstructSomeTypes | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:24:12:24:13 | Tm | subsumes -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:9:7:9:12 | C4> | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:10:7:10:12 | C5> | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:26:7:26:20 | Tuples<,> | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:10:7:10:12 | C4> | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:10:7:10:12 | C4 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:10:7:10:12 | C4 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:11:7:11:12 | C5> | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:11:7:11:12 | C5 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:11:7:11:12 | C5 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:27:7:27:20 | Tuples | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | subsumptionImpliesUnification unifiable -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:9:7:9:12 | C4> | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:10:7:10:12 | C5> | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:32:12:32:23 | (T8,T9) | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:10:7:10:12 | C4> | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:11:7:11:12 | C5> | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | diff --git a/csharp/ql/test/library-tests/unification/Unification.ql b/csharp/ql/test/library-tests/unification/Unification.ql index 7b1dcd26b1c..d3b49c28cde 100644 --- a/csharp/ql/test/library-tests/unification/Unification.ql +++ b/csharp/ql/test/library-tests/unification/Unification.ql @@ -1,10 +1,19 @@ import semmle.code.csharp.Unification -class InterestingType extends Type { +class InterestingType extends @type { InterestingType() { - this.fromSource() or + this.(Type).fromSource() or this.(TupleType).getAChild() instanceof InterestingType } + + string toString() { + result = this.(Type).getQualifiedNameWithTypes() + or + not exists(this.(Type).getQualifiedNameWithTypes()) and + result = this.(Type).toStringWithTypes() + } + + Location getLocation() { result = this.(Type).getLocation() } } query predicate constrainedTypeParameterSubsumes(InterestingType tp, InterestingType t) { @@ -12,9 +21,7 @@ query predicate constrainedTypeParameterSubsumes(InterestingType tp, Interesting } // Should be empty -query predicate constrainedTypeParameterSubsumptionImpliesUnification( - InterestingType tp, InterestingType t -) { +query predicate constrainedTypeParameterSubsumptionImpliesUnification(Type tp, Type t) { tp.(Unification::ConstrainedTypeParameter).subsumes(t) and not tp.(Unification::ConstrainedTypeParameter).unifiable(t) } diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected index d4dd39a1720..31ef1b638e6 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected @@ -1,42 +1,99 @@ -| FormatInvalid.cs:27:24:27:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:27:9:27:32 | call to method Format | this | -| FormatInvalid.cs:30:24:30:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:30:9:30:35 | call to method Format | this | -| FormatInvalid.cs:33:24:33:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:33:9:33:34 | call to method Format | this | -| FormatInvalid.cs:39:27:39:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:39:9:39:40 | call to method Format | this | -| FormatInvalid.cs:42:27:42:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:42:9:42:35 | call to method Format | this | -| FormatInvalid.cs:45:24:45:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:45:9:45:36 | call to method Format | this | -| FormatInvalid.cs:51:24:51:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:51:9:51:29 | call to method Format | this | -| FormatInvalid.cs:75:24:75:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:75:9:75:29 | call to method Format | this | -| FormatInvalid.cs:76:24:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:30 | call to method Format | this | -| FormatInvalid.cs:77:28:77:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:34 | call to method Format | this | -| FormatInvalid.cs:78:24:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:32 | call to method Format | this | -| FormatInvalid.cs:79:24:79:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:35 | call to method Format | this | -| FormatInvalid.cs:80:24:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:38 | call to method Format | this | -| FormatInvalid.cs:82:26:82:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this | -| FormatInvalid.cs:83:26:83:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this | -| FormatInvalid.cs:84:30:84:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this | -| FormatInvalid.cs:85:26:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this | -| FormatInvalid.cs:86:26:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this | -| FormatInvalid.cs:87:26:87:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this | -| FormatInvalid.cs:89:28:89:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this | -| FormatInvalid.cs:90:28:90:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this | -| FormatInvalid.cs:91:28:91:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this | -| FormatInvalid.cs:92:28:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this | -| FormatInvalid.cs:93:28:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this | -| FormatInvalid.cs:95:23:95:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this | -| FormatInvalid.cs:96:23:96:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this | -| FormatInvalid.cs:97:23:97:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this | -| FormatInvalid.cs:98:23:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this | -| FormatInvalid.cs:99:23:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this | -| FormatInvalid.cs:101:45:101:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this | -| FormatInvalid.cs:102:46:102:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this | -| FormatInvalid.cs:103:52:103:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this | -| FormatInvalid.cs:104:48:104:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this | -| FormatInvalid.cs:105:30:105:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this | -| FormatInvalid.cs:107:24:107:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:29 | call to method Write | this | -| FormatInvalid.cs:108:24:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | -| FormatInvalid.cs:109:24:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | -| FormatInvalid.cs:110:24:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | -| FormatInvalid.cs:115:57:115:58 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | -| FormatInvalid.cs:116:19:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | -| FormatInvalid.cs:117:41:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | -| FormatInvalidBad.cs:7:41:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:45 | call to method Format | this | +nodes +| FormatInvalid.cs:9:23:9:27 | "{0}" | semmle.label | "{0}" | +| FormatInvalid.cs:12:23:12:29 | "{0,1}" | semmle.label | "{0,1}" | +| FormatInvalid.cs:15:23:15:31 | "{0, 1}" | semmle.label | "{0, 1}" | +| FormatInvalid.cs:18:23:18:30 | "{0,-1}" | semmle.label | "{0,-1}" | +| FormatInvalid.cs:21:23:21:33 | "{0:0.000}" | semmle.label | "{0:0.000}" | +| FormatInvalid.cs:24:23:24:39 | "{0, -10 :0.000}" | semmle.label | "{0, -10 :0.000}" | +| FormatInvalid.cs:27:23:27:28 | "{ 0}" | semmle.label | "{ 0}" | +| FormatInvalid.cs:30:23:30:31 | "{0,--1}" | semmle.label | "{0,--1}" | +| FormatInvalid.cs:33:23:33:30 | "{0:{}}" | semmle.label | "{0:{}}" | +| FormatInvalid.cs:36:23:36:26 | "%d" | semmle.label | "%d" | +| FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | semmle.label | "{{0}-{1}}" | +| FormatInvalid.cs:42:23:42:28 | "{0}}" | semmle.label | "{0}}" | +| FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | semmle.label | "{foo{0}}" | +| FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | semmle.label | "{{sdc}}" | +| FormatInvalid.cs:51:23:51:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | semmle.label | "new {0} ({1} => {{" | +| FormatInvalid.cs:57:23:57:26 | "{{" | semmle.label | "{{" | +| FormatInvalid.cs:58:23:58:30 | "{{{{}}" | semmle.label | "{{{{}}" | +| FormatInvalid.cs:75:23:75:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:76:23:76:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:77:27:77:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:78:23:78:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:79:23:79:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:80:23:80:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:82:25:82:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:83:25:83:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:84:29:84:31 | "}" | semmle.label | "}" | +| FormatInvalid.cs:85:25:85:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:86:25:86:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:87:25:87:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:89:27:89:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:90:27:90:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:91:27:91:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:92:27:92:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:93:27:93:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:95:22:95:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:96:22:96:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:97:22:97:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:98:22:98:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:99:22:99:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:101:44:101:46 | "}" | semmle.label | "}" | +| FormatInvalid.cs:102:45:102:47 | "}" | semmle.label | "}" | +| FormatInvalid.cs:103:51:103:53 | "}" | semmle.label | "}" | +| FormatInvalid.cs:104:47:104:49 | "}" | semmle.label | "}" | +| FormatInvalid.cs:105:29:105:31 | "}" | semmle.label | "}" | +| FormatInvalid.cs:107:23:107:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:108:23:108:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:109:23:109:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:110:23:110:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:115:56:115:58 | "}" | semmle.label | "}" | +| FormatInvalid.cs:116:18:116:20 | "}" | semmle.label | "}" | +| FormatInvalid.cs:117:40:117:42 | "}" | semmle.label | "}" | +| FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | semmle.label | "class {0} { }" | +| FormatInvalidGood.cs:7:30:7:46 | "class {0} {{ }}" | semmle.label | "class {0} {{ }}" | +edges +#select +| FormatInvalid.cs:27:24:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:27:9:27:32 | call to method Format | this | +| FormatInvalid.cs:30:24:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:30:9:30:35 | call to method Format | this | +| FormatInvalid.cs:33:24:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:33:9:33:34 | call to method Format | this | +| FormatInvalid.cs:39:27:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:39:9:39:40 | call to method Format | this | +| FormatInvalid.cs:42:27:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:42:9:42:35 | call to method Format | this | +| FormatInvalid.cs:45:24:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:45:9:45:36 | call to method Format | this | +| FormatInvalid.cs:51:24:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:51:9:51:29 | call to method Format | this | +| FormatInvalid.cs:75:24:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:75:9:75:29 | call to method Format | this | +| FormatInvalid.cs:76:24:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:30 | call to method Format | this | +| FormatInvalid.cs:77:28:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:34 | call to method Format | this | +| FormatInvalid.cs:78:24:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:32 | call to method Format | this | +| FormatInvalid.cs:79:24:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:35 | call to method Format | this | +| FormatInvalid.cs:80:24:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:38 | call to method Format | this | +| FormatInvalid.cs:82:26:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this | +| FormatInvalid.cs:83:26:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this | +| FormatInvalid.cs:84:30:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this | +| FormatInvalid.cs:85:26:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this | +| FormatInvalid.cs:86:26:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this | +| FormatInvalid.cs:87:26:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this | +| FormatInvalid.cs:89:28:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this | +| FormatInvalid.cs:90:28:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this | +| FormatInvalid.cs:91:28:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this | +| FormatInvalid.cs:92:28:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this | +| FormatInvalid.cs:93:28:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this | +| FormatInvalid.cs:95:23:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this | +| FormatInvalid.cs:96:23:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this | +| FormatInvalid.cs:97:23:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this | +| FormatInvalid.cs:98:23:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this | +| FormatInvalid.cs:99:23:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this | +| FormatInvalid.cs:101:45:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this | +| FormatInvalid.cs:102:46:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this | +| FormatInvalid.cs:103:52:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this | +| FormatInvalid.cs:104:48:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this | +| FormatInvalid.cs:105:30:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this | +| FormatInvalid.cs:107:24:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:29 | call to method Write | this | +| FormatInvalid.cs:108:24:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | +| FormatInvalid.cs:109:24:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | +| FormatInvalid.cs:110:24:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | +| FormatInvalid.cs:115:57:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | +| FormatInvalid.cs:116:19:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | +| FormatInvalid.cs:117:41:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | +| FormatInvalidBad.cs:7:41:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:45 | call to method Format | this | diff --git a/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected b/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected index 36cfa5cf842..ceb279a17b2 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected @@ -1,6 +1,22 @@ -| FormatMissingArgument.cs:11:9:11:31 | call to method Format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this | -| FormatMissingArgument.cs:14:9:14:38 | call to method Format | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | -| FormatMissingArgument.cs:14:9:14:38 | call to method Format | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | -| FormatMissingArgument.cs:28:9:28:32 | call to method Format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this | -| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | -| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | +nodes +| FormatMissingArgument.cs:8:23:8:27 | "{0}" | semmle.label | "{0}" | +| FormatMissingArgument.cs:11:23:11:27 | "{1}" | semmle.label | "{1}" | +| FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | semmle.label | "{2} {3}" | +| FormatMissingArgument.cs:17:23:17:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatMissingArgument.cs:20:23:20:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" | +| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | semmle.label | "{1}" : String | +| FormatMissingArgument.cs:25:24:25:29 | format : String | semmle.label | format : String | +| FormatMissingArgument.cs:28:23:28:28 | access to parameter format | semmle.label | access to parameter format | +| FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" | +| FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | semmle.label | "Hello {1} {2}" | +| FormatMissingArgumentGood.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" | +edges +| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:25:24:25:29 | format : String | +| FormatMissingArgument.cs:25:24:25:29 | format : String | FormatMissingArgument.cs:28:23:28:28 | access to parameter format | +#select +| FormatMissingArgument.cs:11:9:11:31 | call to method Format | FormatMissingArgument.cs:11:23:11:27 | "{1}" | FormatMissingArgument.cs:11:23:11:27 | "{1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this | +| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | +| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | +| FormatMissingArgument.cs:28:9:28:32 | call to method Format | FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:28:23:28:28 | access to parameter format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this | +| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | +| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | diff --git a/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected b/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected index 35387ecb228..db2726ea591 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected @@ -1,13 +1,31 @@ -| FormatUnusedArgument.cs:11:9:11:29 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:11:23:11:25 | "X" | format string | FormatUnusedArgument.cs:11:28:11:28 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:14:9:14:34 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | format string | FormatUnusedArgument.cs:14:33:14:33 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:17:9:17:38 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:17:37:17:37 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:20:9:20:38 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:20:34:20:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:34:23:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:37:23:37 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:40:23:40 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:26:9:26:35 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:26:34:26:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:38:9:38:33 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | format string | FormatUnusedArgument.cs:38:32:38:32 | (...) ... | this supplied value | -| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value | -| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value | -| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value | -| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value | +nodes +| FormatUnusedArgument.cs:8:23:8:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatUnusedArgument.cs:11:23:11:25 | "X" | semmle.label | "X" | +| FormatUnusedArgument.cs:14:23:14:27 | "{0}" | semmle.label | "{0}" | +| FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | semmle.label | "{0} {0}" | +| FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | semmle.label | "{1} {1}" | +| FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | semmle.label | "abcdefg" | +| FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | semmle.label | "{{sdc}}" | +| FormatUnusedArgument.cs:29:23:29:33 | "{{{0:D}}}" | semmle.label | "{{{0:D}}}" | +| FormatUnusedArgument.cs:32:23:32:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" | +| FormatUnusedArgument.cs:35:23:35:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | semmle.label | "{{0}}" | +| FormatUnusedArgument.cs:42:23:42:24 | "" | semmle.label | "" | +| FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | semmle.label | "Error processing file: {0}" | +| FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | semmle.label | "Error processing file: {1} ({1})" | +| FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | semmle.label | "Error processing file: %s (%d)" | +edges +#select +| FormatUnusedArgument.cs:11:9:11:29 | call to method Format | FormatUnusedArgument.cs:11:23:11:25 | "X" | FormatUnusedArgument.cs:11:23:11:25 | "X" | The $@ ignores $@. | FormatUnusedArgument.cs:11:23:11:25 | "X" | format string | FormatUnusedArgument.cs:11:28:11:28 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:14:9:14:34 | call to method Format | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | The $@ ignores $@. | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | format string | FormatUnusedArgument.cs:14:33:14:33 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:17:9:17:38 | call to method Format | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | The $@ ignores $@. | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:17:37:17:37 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:20:9:20:38 | call to method Format | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | The $@ ignores $@. | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:20:34:20:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:34:23:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:37:23:37 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:40:23:40 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:26:9:26:35 | call to method Format | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | The $@ ignores $@. | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:26:34:26:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:38:9:38:33 | call to method Format | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | The $@ ignores $@. | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | format string | FormatUnusedArgument.cs:38:32:38:32 | (...) ... | this supplied value | +| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value | +| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value | +| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value | +| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected index 254f5581744..a87ff6764ce 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected @@ -1,15 +1,13 @@ edges -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:25:32:25:51 | access to property Text : String | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:27:26:47 | ... + ... | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:50:26:66 | ... + ... | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:63:28:71 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:74:28:82 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:32:39:32:47 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:33:40:33:48 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:34:47:34:55 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:27:26:47 | ... + ... | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:50:26:66 | ... + ... | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:63:28:71 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:74:28:82 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:32:39:32:47 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:33:40:33:48 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:34:47:34:55 | access to local variable userInput | nodes | CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | semmle.label | access to property Text : String | | CommandInjection.cs:26:27:26:47 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:26:50:26:66 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:28:63:28:71 | access to local variable userInput | semmle.label | access to local variable userInput | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected index 8f04dc6f81a..a661a86c71c 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected @@ -1,10 +1,14 @@ edges -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:26:32:26:51 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:27:29:27:48 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | +| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:25:48:25:67 | access to property Text : String | +| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | +| XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | XSS.cs:26:32:26:51 | call to method ToString | +| XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | XSS.cs:27:29:27:48 | call to method ToString | +| XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | XSS.cs:28:26:28:45 | call to method ToString | | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | -| XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | @@ -19,7 +23,6 @@ edges | XSS.cs:28:26:28:45 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | | XSS.cs:38:36:38:39 | access to local variable name | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:59:22:59:25 | access to local variable name | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:69:13:69:49 | access to property OutputStream | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:76:36:76:39 | access to local variable name | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:79:36:79:40 | access to local variable name2 | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | User-provided value | | XSS.cs:86:28:86:31 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected index 61dffee741f..b035cc46b1b 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected @@ -1,16 +1,12 @@ edges -| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:38:21:38:40 | access to property Text : String | -| SqlInjection.cs:38:21:38:40 | access to property Text : String | SqlInjection.cs:39:50:39:55 | access to local variable query1 | -| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:73:33:73:52 | access to property Text : String | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:74:56:74:61 | access to local variable query1 | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:75:55:75:60 | access to local variable query1 | +| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:39:50:39:55 | access to local variable query1 | +| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:74:56:74:61 | access to local variable query1 | +| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:75:55:75:60 | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | SqlInjection.cs:88:50:88:55 | access to local variable query1 | nodes | SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| SqlInjection.cs:38:21:38:40 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:39:50:39:55 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:74:56:74:61 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:75:55:75:60 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | semmle.label | access to property Text : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected index b6aff7ad8aa..8e051c94464 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected @@ -1,6 +1,11 @@ edges -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | +| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | @@ -10,8 +15,13 @@ nodes | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | semmle.label | call to method InsecureRandomString | | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | semmle.label | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | semmle.label | call to method InsecureRandomStringFromIndexer | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | semmle.label | [post] access to local variable data [[]] : Int32 | | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | semmle.label | (...) ... : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | semmle.label | [post] access to local variable result [[]] : String | +| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | semmle.label | call to method GetString : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | semmle.label | access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | semmle.label | access to local variable result [[]] : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | semmle.label | call to method ToString : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected index c969d8a9bef..7898c01c3b5 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected @@ -1,33 +1,23 @@ edges | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | -| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | ConditionalBypass.cs:24:13:24:45 | call to method Equals | -| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | ConditionalBypass.cs:29:13:29:40 | ... == ... | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:45 | call to method Equals | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:40 | ... == ... | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:46 | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | -| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | ConditionalBypass.cs:46:13:46:46 | ... == ... | -| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | -| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | ConditionalBypass.cs:74:13:74:40 | ... == ... | -| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | -| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | ConditionalBypass.cs:86:13:86:40 | ... == ... | +| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:40 | ... == ... | +| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:40 | ... == ... | nodes | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | ConditionalBypass.cs:18:13:18:30 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:24:13:24:45 | call to method Equals | semmle.label | call to method Equals | -| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:29:13:29:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | semmle.label | call to method GetHostByAddress : IPHostEntry | -| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | semmle.label | access to property HostName : String | | ConditionalBypass.cs:46:13:46:46 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:51:13:51:29 | access to property HostName | semmle.label | access to property HostName | | ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:74:13:74:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:86:13:86:40 | ... == ... | semmle.label | ... == ... | #select | ConditionalBypass.cs:19:13:19:33 | call to method login | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | ConditionalBypass.cs:18:13:18:30 | ... == ... | this condition | ConditionalBypass.cs:14:26:14:48 | access to property QueryString | user input | diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme new file mode 100644 index 00000000000..ad622770b3c --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme @@ -0,0 +1,1893 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..f2aa2d4ac31 --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme @@ -0,0 +1,1889 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties new file mode 100644 index 00000000000..c589f1a646e --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed relations `is_constructed` and `is_generic` +compatibility: full +is_generic.rel: delete +is_constructed.rel: delete diff --git a/docs/language/README.rst b/docs/language/README.rst index 2436335932e..55232361199 100644 --- a/docs/language/README.rst +++ b/docs/language/README.rst @@ -18,8 +18,7 @@ Project structure The documentation currently consists of the following Sphinx projects: - ``learn-ql``–help topics to help you learn CodeQL and write queries -- ``ql-handbook``–a user-friendly guide to the QL language, which underlies CodeQL analysis -- ``ql-spec``–formal descriptions of the QL language and QLDoc comments +- ``ql-handbook``–an overview of important concepts in QL, the language that underlies CodeQL analysis - ``support``–the languages and frameworks currently supported in CodeQL analysis - ``ql-training``–source files for the CodeQL training and variant analysis examples slide decks diff --git a/docs/language/learn-ql/beginner/catch-the-fire-starter.rst b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst index 72f3f4f7685..32ac89e27d6 100644 --- a/docs/language/learn-ql/beginner/catch-the-fire-starter.rst +++ b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst @@ -147,6 +147,4 @@ You have found the two fire starters! They are arrested and the villagers are on Further reading --------------- -- Find out who will be the new ruler of the village in the :doc:`next tutorial `. -- Learn more about predicates and classes in the `QL language reference `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/cross-the-river.rst b/docs/language/learn-ql/beginner/cross-the-river.rst index 3f5307d98d5..33eaeea2f2e 100644 --- a/docs/language/learn-ql/beginner/cross-the-river.rst +++ b/docs/language/learn-ql/beginner/cross-the-river.rst @@ -262,4 +262,9 @@ Here are some more example queries that solve the river crossing puzzle: #. This query introduces `algebraic datatypes `__ to model the situation, instead of defining everything as a subclass of ``string``. - ➤ `See solution in the query console on LGTM.com `__ \ No newline at end of file + ➤ `See solution in the query console on LGTM.com `__ + +Further reading +--------------- + +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst index df3cd61fde9..aaf7e552a1c 100644 --- a/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst +++ b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst @@ -161,6 +161,4 @@ You could also try writing more of your own QL queries to find interesting facts Further reading --------------- -- Learn more about recursion in the `QL language reference `__. -- Put your QL skills to the test and solve the :doc:`River crossing puzzle `. -- Start using QL to analyze projects. See :doc:`Learning CodeQL <../../index>` for a summary of the available languages and resources. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/find-the-thief.rst b/docs/language/learn-ql/beginner/find-the-thief.rst index 02f19cce325..6111590d603 100644 --- a/docs/language/learn-ql/beginner/find-the-thief.rst +++ b/docs/language/learn-ql/beginner/find-the-thief.rst @@ -292,6 +292,4 @@ Have you found the thief? Further reading --------------- -- Help the villagers track down another criminal in the :doc:`next tutorial `. -- Find out more about the concepts you discovered in this tutorial in the `QL language reference `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/conversions-classes.rst b/docs/language/learn-ql/cpp/conversions-classes.rst index 553423bb47e..b1e5c976fb5 100644 --- a/docs/language/learn-ql/cpp/conversions-classes.rst +++ b/docs/language/learn-ql/cpp/conversions-classes.rst @@ -223,8 +223,5 @@ There is a similar built-in `query `__ on LG Further reading --------------- -- Explore other ways of querying classes using examples from the `C/C++ cookbook `__. -- Take a look at the :doc:`Analyzing data flow in C and C++ ` tutorial. -- Try the worked examples in the following topics: :doc:`Refining a query to account for edge cases `, and :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/dataflow.rst b/docs/language/learn-ql/cpp/dataflow.rst index dcdc7aab1d4..c988fee9f9c 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -299,13 +299,6 @@ Exercise 3: Write a class that represents flow sources from ``getenv``. (`Answer Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from ``getenv`` to ``gethostbyname``. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Try the worked examples in the following topics: :doc:`Refining a query to account for edge cases ` and :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. - Answers ------- @@ -393,3 +386,11 @@ Exercise 4 from DataFlow::Node getenv, FunctionCall fc, GetenvToGethostbynameConfiguration cfg where cfg.hasFlow(getenv, DataFlow::exprNode(fc.getArgument(0))) select getenv.asExpr(), fc + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/cpp/expressions-types.rst b/docs/language/learn-ql/cpp/expressions-types.rst index 39da25330d3..18bdae52ebc 100644 --- a/docs/language/learn-ql/cpp/expressions-types.rst +++ b/docs/language/learn-ql/cpp/expressions-types.rst @@ -132,7 +132,5 @@ Note that we replaced ``e.getEnclosingStmt()`` with ``e.getEnclosingStmt().getPa Further reading --------------- -- Explore other ways of finding types and statements using examples from the C/C++ cookbook for `types `__ and `statements `__. -- Take a look at the :doc:`Conversions and classes in C and C++ ` and :doc:`Analyzing data flow in C and C++ ` tutorials. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/function-classes.rst b/docs/language/learn-ql/cpp/function-classes.rst index 841add0d4b0..38f53f2354b 100644 --- a/docs/language/learn-ql/cpp/function-classes.rst +++ b/docs/language/learn-ql/cpp/function-classes.rst @@ -92,7 +92,5 @@ The LGTM version of this query is considerably more complicated, but if you look Further reading --------------- -- Explore other ways of finding functions using examples from the `C/C++ cookbook `__. -- Take a look at some other tutorials: :doc:`Expressions, types and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/guards.rst b/docs/language/learn-ql/cpp/guards.rst index 409df0a8f81..960c033a6fb 100644 --- a/docs/language/learn-ql/cpp/guards.rst +++ b/docs/language/learn-ql/cpp/guards.rst @@ -93,3 +93,9 @@ The ``comparesLt`` predicate ``comparesLt(left, right, k, isLessThan, testIsTrue)`` holds if ``left < right + k`` evaluates to ``isLessThan`` when the expression evaluates to ``testIsTrue``. +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst + diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index 4960cfc5dba..02fdff8a9e0 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -525,6 +525,5 @@ This table lists `Preprocessor `, :doc:`Expressions, types, and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/private-field-initialization.rst b/docs/language/learn-ql/cpp/private-field-initialization.rst index c1f9224a145..56039812aed 100644 --- a/docs/language/learn-ql/cpp/private-field-initialization.rst +++ b/docs/language/learn-ql/cpp/private-field-initialization.rst @@ -149,6 +149,5 @@ Finally we can simplify the query by using the transitive closure operator. In t Further reading --------------- -- Take a look at another example: :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/ql-for-cpp.rst b/docs/language/learn-ql/cpp/ql-for-cpp.rst index bd52291a7f8..594ce7288d9 100644 --- a/docs/language/learn-ql/cpp/ql-for-cpp.rst +++ b/docs/language/learn-ql/cpp/ql-for-cpp.rst @@ -39,10 +39,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Using range analysis for C and C++ `: You can use range analysis to determine the upper or lower bounds on an expression, or whether an expression could potentially over or underflow. - :doc:`Hash consing and value numbering `: You can use specialized CodeQL libraries to recognize expressions that are syntactically identical or compute the same value at runtime in C and C++ codebases. - -Further reading ---------------- - -- For examples of how to query common C/C++ elements, see the `C/C++ cookbook `__. -- For the queries used in LGTM, display a `C/C++ query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for C/C++ see the `CodeQL library for C/C++ `__. diff --git a/docs/language/learn-ql/cpp/range-analysis.rst b/docs/language/learn-ql/cpp/range-analysis.rst index ba324e86ac9..9bd9dc7578e 100644 --- a/docs/language/learn-ql/cpp/range-analysis.rst +++ b/docs/language/learn-ql/cpp/range-analysis.rst @@ -41,3 +41,9 @@ This query uses ``upperBound`` to determine whether the result of ``snprintf`` i convSink = call.getArgument(1).getFullyConverted() select call, upperBound(call.getArgument(1).getFullyConverted()) + +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst index de102a15f6d..4fd22bb115b 100644 --- a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst +++ b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst @@ -110,3 +110,9 @@ Example query hashCons(outer.getCondition()) = hashCons(inner.getCondition()) select inner.getCondition(), "The condition of this if statement duplicates the condition of $@", outer.getCondition(), "an enclosing if statement" + +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/cpp/zero-space-terminator.rst b/docs/language/learn-ql/cpp/zero-space-terminator.rst index a25437865f7..98aec9c9e4e 100644 --- a/docs/language/learn-ql/cpp/zero-space-terminator.rst +++ b/docs/language/learn-ql/cpp/zero-space-terminator.rst @@ -224,5 +224,5 @@ The completed query will now identify cases where the result of ``strlen`` is st Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/dataflow.rst b/docs/language/learn-ql/csharp/dataflow.rst index 317594b33f2..67414562893 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -553,6 +553,7 @@ This can be adapted from the ``SystemUriFlow`` class: Further reading --------------- -- Learn about the standard libraries used to write queries for C# in :doc:`Introducing the C# libraries `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/csharp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst index f262478dc44..5098ba77671 100644 --- a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst +++ b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst @@ -1122,6 +1122,5 @@ Here is the fixed version: Further reading --------------- -- Visit :doc:`Analyzing data flow in C# ` to learn more about writing queries using the standard data flow and taint tracking libraries. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/csharp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/ql-for-csharp.rst b/docs/language/learn-ql/csharp/ql-for-csharp.rst index 6eb3567e808..96c87348036 100644 --- a/docs/language/learn-ql/csharp/ql-for-csharp.rst +++ b/docs/language/learn-ql/csharp/ql-for-csharp.rst @@ -15,9 +15,4 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Analyzing data flow in C# `: You can use CodeQL to track the flow of data through a C# program to its use. -Further reading ---------------- -- For examples of how to query common C# elements, see the `C# cookbook `__. -- For the queries used in LGTM, display a `C# query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for C# see the `CodeQL library for C# `__. diff --git a/docs/language/learn-ql/go/ast-class-reference.rst b/docs/language/learn-ql/go/ast-class-reference.rst new file mode 100644 index 00000000000..bc23fec39dc --- /dev/null +++ b/docs/language/learn-ql/go/ast-class-reference.rst @@ -0,0 +1,483 @@ +Abstract syntax tree classes for working with Go programs +========================================================= + +CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. + +.. include:: ../../reusables/abstract-syntax-tree.rst + +Statement classes +----------------- + +This table lists all subclasses of `Stmt `__. + ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Statement syntax | CodeQL class | Superclasses | Remarks | ++===================================================================================================================+===================================================================================================================+===============================================================================================================+===================================================================================================================+ +| ``;`` | EmptyStmt_ | | | +| | | | | +| | .. _EmptyStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$EmptyStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ | ExprStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ExprStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExprStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``{`` Stmt_ ``...`` ``}`` | BlockStmt_ | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``if`` Expr_ BlockStmt_ | IfStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _IfStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IfStmt.html | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``if`` Expr_ BlockStmt_ ``else`` Stmt_ | | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``if`` Stmt_\ ``;`` Expr_ BlockStmt_ | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``for`` Expr_ BlockStmt_ | ForStmt_ | LoopStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ForStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ForStmt.html | .. _LoopStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LoopStmt.html | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``for`` Stmt_\ ``;`` Expr_\ ``;`` Stmt_ BlockStmt_ | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``for`` Expr_ ``...`` ``=`` ``range`` Expr_ BlockStmt_ | RangeStmt_ | LoopStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RangeStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RangeStmt.html | .. _LoopStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LoopStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``switch`` Expr_ ``{`` CaseClause_ ``...`` ``}`` | ExpressionSwitchStmt_ | SwitchStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ExpressionSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExpressionSwitchStmt.html | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` Stmt_\ ``;`` Expr_ ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``switch`` Expr_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | TypeSwitchStmt_ | SwitchStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _TypeSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$TypeSwitchStmt.html | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` SimpleAssignStmt_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` Stmt_\ ``;`` Expr_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``select`` ``{`` CommClause_ ``...`` ``}`` | SelectStmt_ | | | +| | | | | +| .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | .. _SelectStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SelectStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``return`` | ReturnStmt_ | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``return`` Expr_ ``...`` | .. _ReturnStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ReturnStmt.html | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``break`` | BreakStmt_ | BranchStmt_ | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``break`` LabelName_ | .. _BreakStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BreakStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``continue`` | ContinueStmt_ | BranchStmt_ | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``continue`` LabelName_ | .. _ContinueStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ContinueStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``goto`` LabelName_ | GotoStmt_ | BranchStmt_ | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | .. _GotoStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$GotoStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``fallthrough`` | FallthroughStmt_ | BranchStmt_ | can only occur as final non-empty child of a CaseClause_ in an ExpressionSwitchStmt_ | +| | | | | +| | .. _FallthroughStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$FallthroughStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | +| | | | .. _ExpressionSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExpressionSwitchStmt.html | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| LabelName_\ ``:`` Stmt_ | LabeledStmt_ | | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | .. _LabeledStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LabeledStmt.html | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``var`` VariableName_ TypeName_ | DeclStmt_ | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | .. _DeclStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DeclStmt.html | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``const`` VariableName_ ``=`` Expr_ | | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``type`` TypeName_ TypeExpr_ | | | | +| | | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``type`` TypeName_ ``=`` TypeExpr_ | | | | +| | | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``...`` ``=`` Expr_ ``...`` | AssignStmt_ | SimpleAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AssignStmt.html | .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| VariableName_ ``...`` ``:=`` Expr_ ``...`` | DefineStmt_ | SimpleAssignStmt_, Assignment_ | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | .. _DefineStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DefineStmt.html | .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``+=`` Expr_ | AddAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AddAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AddAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``-=`` Expr_ | SubAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _SubAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SubAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``*=`` Expr_ | MulAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _MulAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$MulAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``/=`` Expr_ | QuoAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _QuoAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$QuoAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``%=`` Expr_ | RemAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RemAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RemAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``*=`` Expr_ | MulAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _MulAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$MulAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``&=`` Expr_ | AndAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AndAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AndAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``|=`` Expr_ | OrAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _OrAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$OrAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``^=`` Expr_ | XorAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _XorAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$XorAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``<<=`` Expr_ | ShlAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ShlAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ShlAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``>>=`` Expr_ | ShrAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ShrAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ShrAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``&^=`` Expr_ | AndNotAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AndNotAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AndNotAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``++`` | IncStmt_ | IncDecStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _IncStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncStmt.html | .. _IncDecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncDecStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``--`` | DecStmt_ | IncDecStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _DecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DecStmt.html | .. _IncDecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncDecStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``go`` CallExpr_ | GoStmt_ | | | +| | | | | +| .. _CallExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallExpr.html | .. _GoStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$GoStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``defer`` CallExpr_ | DeferStmt_ | | | +| | | | | +| .. _CallExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallExpr.html | .. _DeferStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DeferStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``<-`` Expr_ | SendStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _SendStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SendStmt.html | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``case`` Expr_ ``...``\ ``:`` Stmt_ ``...`` | CaseClause_ | | can only occur as child of a SwitchStmt_ | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``case`` TypeExpr_ ``...``\ ``:`` Stmt_ ``...`` | | | | +| | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``default:`` Stmt_ ``...`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``case`` SendStmt_\ ``:`` Stmt_ ``...`` | CommClause_ | | can only occur as child of a SelectStmt_ | +| | | | | +| .. _SendStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SendStmt.html | .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | | .. _SelectStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SelectStmt.html | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``case`` RecvStmt_\ ``:`` Stmt_ ``...`` | | | | +| | | | | +| .. _RecvStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RecvStmt.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``default:`` Stmt_ ``...`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``...`` ``=`` RecvExpr_ | RecvStmt_ | | can only occur as child of a CommClause_ | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RecvStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RecvStmt.html | | .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | +| .. _RecvExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| VariableName_ ``...`` ``:=`` RecvExpr_ | | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | | | | +| .. _RecvExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| (anything unparseable) | BadStmt_ | | | +| | | | | +| | .. _BadStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BadStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ + +Expression classes +------------------ + +There are many expression classes, so we present them by category. +All classes in this section are subclasses of +`Expr `__. + +Literals +~~~~~~~~ + ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax example | CodeQL class | Superclass | ++=========================================+==============================================================================================+====================================================================================================+ +| ``23`` | `IntLit `__ | `BasicLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``4.2`` | `FloatLit `__ | `BasicLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``4.2 + 2.7i`` | `ImagLit `__ | `BasicLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``'a'`` | `CharLit `__ | `BasicLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``"Hello"`` | `StringLit `__ | `BasicLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``func(x, y int) int { return x + y }`` | `FuncLit `__ | `FuncDef `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``map[string]int{"A": 1, "B": 2}`` | `MapLit `__ | `CompositeLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``Point3D{0.5, -0.5, 0.5}`` | `StructLit `__ | `CompositeLit `__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +Unary expressions +~~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`UnaryExpr `__. + ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++============================================================================================+========================================================================================================+==================================================================================================================+ +| ``+``\ `Expr `__ | `PlusExpr `__ | `ArithmeticUnaryExpr `__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``-``\ `Expr `__ | `MinusExpr `__ | `ArithmeticUnaryExpr `__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``!``\ `Expr `__ | `NotExpr `__ | `LogicalUnaryExpr `__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``^``\ `Expr `__ | `ComplementExpr `__ | `BitwiseUnaryExpr `__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``&``\ `Expr `__ | `AddressExpr `__ | | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``<-``\ `Expr `__ | `RecvExpr `__ | | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + +Binary expressions +~~~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`BinaryExpr `__. + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++==============================================================================================================================================================================+================================================================================================+============================================================================================================================+ +| `Expr `__ ``*`` `Expr `__ | `MulExpr `__ | `ArithmeticBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``/`` `Expr `__ | `QuoExpr `__ | `ArithmeticBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``%`` `Expr `__ | `RemExpr `__ | `ArithmeticBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``+`` `Expr `__ | `AddExpr `__ | `ArithmeticBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``-`` `Expr `__ | `SubExpr `__ | `ArithmeticBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``<<`` `Expr `__ | `ShlExpr `__ | `ShiftExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``>>`` `Expr `__ | `ShrExpr `__ | `ShiftExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``&&`` `Expr `__ | `LandExpr `__ | `LogicalBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``||`` `Expr `__ | `LorExpr `__ | `LogicalBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``<`` `Expr `__ | `LssExpr `__ | `RelationalComparisonExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``>`` `Expr `__ | `GtrExpr `__ | `RelationalComparisonExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``<=`` `Expr `__ | `LeqExpr `__ | `RelationalComparisonExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``>=`` `Expr `__ | `GeqExpr `__ | `RelationalComparisonExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``==`` `Expr `__ | `EqlExpr `__ | `EqualityTestExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``!=`` `Expr `__ | `NeqExpr `__ | `EqualityTestExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``&`` `Expr `__ | `AndExpr `__ | `BitwiseBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``|`` `Expr `__ | `OrExpr `__ | `BitwiseBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``^`` `Expr `__ | `XorExpr `__ | `BitwiseBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__ ``&^`` `Expr `__ | `AndNotExpr `__ | `BitwiseBinaryExpr `__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ + +Type expressions +~~~~~~~~~~~~~~~~ + +These classes represent different expressions for types. They do +not have a common superclass. + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++=========================================================================================================================================================================================================+====================================================================================================================+====================================================================================================+ +| ``[``\ `Expr `__\ ``]`` `TypeExpr `__ | `ArrayTypeExpr `__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``struct { ... }`` | `StructTypeExpr `__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``func`` `FunctionName `__\ ``(...) (...)`` | `FuncTypeExpr `__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``interface { ... }`` | `InterfaceTypeExpr `__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``map[``\ `TypeExpr `__\ ``]``\ `TypeExpr `__ | `MapTypeExpr `__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``chan<-`` `TypeExpr `__ | `SendChanTypeExpr `__ | `ChanTypeExpr `__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``<-chan`` `TypeExpr `__ | `RecvChanTypeExpr `__ | `ChanTypeExpr `__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``chan`` `TypeExpr `__ | `SendRecvChanTypeExpr `__ | `ChanTypeExpr `__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +Name expressions +~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`Name `__. + +The following classes relate to the structure of the name. + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++===================================================================================================================================================================================+======================================================================================================+====================================================================================================+ +| `Ident `__ | `SimpleName `__ | `Ident `__ | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| `Ident `__\ ``.``\ `Ident `__ | `QualifiedName `__ | `SelectorExpr `__ | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +The following classes relate to what sort of entity the name refers to. + + +- `PackageName `__ +- `TypeName `__ +- `LabelName `__ +- `ValueName `__ + + - `ConstantName `__ + - `VariableName `__ + - `FunctionName `__ + +Miscellaneous +~~~~~~~~~~~~~ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | Remarks | ++============================================================================================================================================================================================================================================================================================================================================================================+========================================================================================================+====================================================================================================================+==========================================================================================================================================================================================================================+ +| ``foo`` | `Ident `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``_`` | `BlankIdent `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``...`` | `Ellipsis `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``(``\ `Expr `__\ ``)`` | `ParenExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Ident `__\ ``.``\ `Ident `__ | `SelectorExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__\ ``[``\ `Expr `__\ ``]`` | `IndexExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__\ ``[``\ `Expr `__\ ``:``\ `Expr `__\ ``:``\ `Expr `__\ ``]`` | `SliceExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__\ ``.(``\ `TypeExpr `__\ ``)`` | `TypeAssertExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``*``\ `Expr `__ | `StarExpr `__ | | can be a `ValueExpr `__ or `TypeExpr `__ depending on context | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__\ ``:`` `Expr `__ | `KeyValueExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `TypeExpr `__\ ``(``\ `Expr `__\ ``)`` | `ConversionExpr `__ | `CallOrConversionExpr `__ | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr `__\ ``(...)`` | `CallExpr `__ | `CallOrConversionExpr `__ | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| (anything unparseable) | `BadExpr `__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +The following classes organize expressions by the kind of entity they refer to. + ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CodeQL class | Explanation | ++======================================================================================================+=========================================================================================================================================================================================================================================================+ +| `TypeExpr `__ | an expression that denotes a type | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `ReferenceExpr `__ | an expression that refers to a variable, a constant, a function, a field, or an element of an array or a slice | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `ValueExpr `__ | an expression that can be evaluated to a value (as opposed to expressions that refer to a package, a type, or a statement label). This generalizes `ReferenceExpr `__ | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/go-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/go/introduce-libraries-go.rst b/docs/language/learn-ql/go/introduce-libraries-go.rst index e47ce2b94c4..17315a67e13 100644 --- a/docs/language/learn-ql/go/introduce-libraries-go.rst +++ b/docs/language/learn-ql/go/introduce-libraries-go.rst @@ -99,9 +99,8 @@ The most important subclasses of `AstNode statements and expressions, respectively. This section briefly discusses some of their more important subclasses and predicates. For a full reference of all the subclasses of `Stmt `__ and `Expr -`__ and their API, see -`Stmt.qll `__ and `Expr.qll -`__. +`__, see +:doc:`Abstract syntax tree classes for Go `. Statements ~~~~~~~~~~ @@ -611,8 +610,8 @@ is to compare them to each other to determine whether two data-flow nodes have t Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/go-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst .. |ast| image:: ast.png .. |cfg| image:: cfg.png diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index c977bb6838a..9463dc04024 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -7,14 +7,10 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat :hidden: introduce-libraries-go + ast-class-reference - `Basic Go query `__: Learn to write and run a simple CodeQL query using LGTM. - :doc:`CodeQL library for Go `: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go. -Further reading ---------------- - -- For examples of how to query common Go elements, see the `Go cookbook `__. -- For the queries used in LGTM, display a `Go query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for Go see the `CodeQL library for Go `__. \ No newline at end of file +- :doc:`Abstract syntax tree classes for working with Go programs `: CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. diff --git a/docs/language/learn-ql/intro-to-data-flow.rst b/docs/language/learn-ql/intro-to-data-flow.rst index e509d3a8c16..b66ef886eb8 100644 --- a/docs/language/learn-ql/intro-to-data-flow.rst +++ b/docs/language/learn-ql/intro-to-data-flow.rst @@ -79,8 +79,7 @@ However, since ``y`` is derived from ``x``, it is influenced by the untrusted or In QL, taint tracking extends data flow analysis by including steps in which the data values are not necessarily preserved, but the potentially insecure object is still propagated. These flow steps are modeled in the taint-tracking library using predicates that hold if taint is propagated between nodes. -What next? -********** +Further reading +*************** -- Search for ``DataFlow`` and ``TaintTracking`` in the `standard CodeQL libraries `__ to learn more about the technical implementation of data flow analysis for specific programming languages. -- Visit `Learning CodeQL `__ to find language-specific tutorials on data flow and other topics. +- `Exploring data flow with path queries `__ diff --git a/docs/language/learn-ql/java/annotations.rst b/docs/language/learn-ql/java/annotations.rst index 497f20e1ff3..861cbb74268 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -49,7 +49,7 @@ We could then write this query to find all ``@SuppressWarnings`` annotations att anntp.hasQualifiedName("java.lang", "SuppressWarnings") select ann, ann.getValue("value") -➤ `See the full query in the query console on LGTM.com `__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. +➤ `See the full query in the query console on LGTM.com `__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. As another example, this query finds all annotation types that only have a single annotation element, which has name ``value``: @@ -64,7 +64,7 @@ As another example, this query finds all annotation types that only have a singl ) select anntp -➤ `See the full query in the query console on LGTM.com `__. +➤ `See the full query in the query console on LGTM.com `__. Example: Finding missing ``@Override`` annotations -------------------------------------------------- @@ -122,7 +122,7 @@ This makes it very easy to write our query for finding methods that override ano not overriding.getAnAnnotation() instanceof OverrideAnnotation select overriding, "Method overrides another method, but does not have an @Override annotation." -➤ `See this in the query console on LGTM.com `__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. +➤ `See this in the query console on LGTM.com `__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. Example: Finding calls to deprecated methods -------------------------------------------- @@ -192,13 +192,13 @@ For instance, consider this slightly updated example: .. code-block:: java class A { - @Deprecated void m() {} + @Deprecated void m() {} - @Deprecated void n() { - m(); - } + @Deprecated void n() { + m(); + } - @SuppressWarnings("deprecated") + @SuppressWarnings("deprecated") void r() { m(); } @@ -235,11 +235,10 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress and not call.getCaller().getAnAnnotation() instanceof SuppressDeprecationWarningAnnotation select call, "This call invokes a deprecated method." -➤ `See this in the query console on LGTM.com `__. It's fairly common for projects to contain calls to methods that appear to be deprecated. +➤ `See this in the query console on LGTM.com `__. It's fairly common for projects to contain calls to methods that appear to be deprecated. Further reading --------------- -- Take a look at some of the other articles in this section: :doc:`Javadoc ` and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index f34e2eec764..4892ec0c662 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -1,82 +1,76 @@ -Classes for working with Java code -================================== +Abstract syntax tree classes for working with Java programs +=========================================================== -CodeQL has a large selection of classes for working with Java statements and expressions. +CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs. -.. _Expr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Expr.html -.. _Stmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html -.. _VarAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html -.. _SwitchCase: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchCase.html -.. _TypeAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html -.. _Member: https://help.semmle.com/qldoc/java/semmle/code/java/Member.qll/type.Member$Member.html -.. _Literal: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html +.. include:: ../../reusables/abstract-syntax-tree.rst Statement classes ----------------- This table lists all subclasses of `Stmt`_. -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| Statement syntax | CodeQL class | Superclasses | Remarks | -+========================================================================+===========================================================================================================================================================+===================================+=============================================+ -| ``;`` | `EmptyStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| `Expr`_ ``;`` | `ExprStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``{`` `Stmt`_ ``... }`` | `Block `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``if (`` `Expr`_ ``)`` `Stmt`_ ``else`` `Stmt`_ | `IfStmt `__ | ``ConditionalStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``if (`` `Expr`_ ``)`` `Stmt`_ | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``while (`` `Expr`_ ``)`` `Stmt`_ | `WhileStmt `__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``do`` `Stmt`_ ``while (`` `Expr`_ ``)`` | `DoStmt `__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``for (`` `Expr`_ ``;`` `Expr`_ ``;`` `Expr`_ ``)`` `Stmt`_ | `ForStmt `__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``for (`` `VarAccess`_ ``:`` `Expr`_ ``)`` `Stmt`_ | `EnhancedForStmt `__ | ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``switch (`` `Expr`_ ``) {`` `SwitchCase`_ ``... }`` | `SwitchStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``try {`` `Stmt`_ ``... } finally {`` `Stmt`_ ``... }`` | `TryStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``return`` `Expr`_ ``;`` | `ReturnStmt `__ | | | -+------------------------------------------------------------------------+ + + + -| ``return ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``throw`` `Expr`_ ``;`` | `ThrowStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``break ;`` | `BreakStmt `__ | ``JumpStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``break label ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``continue ;`` | `ContinueStmt `__ | ``JumpStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``continue label ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``label :`` `Stmt`_ | `LabeledStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``synchronized (`` `Expr`_ ``)`` `Stmt`_ | `SynchronizedStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``assert`` `Expr`_ ``:`` `Expr`_ ``;`` | `AssertStmt `__ | | | -+------------------------------------------------------------------------+ + + + -| ``assert`` `Expr`_ ``;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| `TypeAccess`_ ``name ;`` | `LocalVariableDeclStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``class name {`` `Member`_ ``... } ;`` | `LocalClassDeclStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``this (`` `Expr`_ ``, ... ) ;`` | `ThisConstructorInvocationStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``super (`` `Expr`_ ``, ... ) ;`` | `SuperConstructorInvocationStmt `__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``catch (`` `TypeAccess`_ ``name ) {`` `Stmt`_ ``... }`` | `CatchClause `__ | | can only occur as child of a ``TryStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``case`` `Literal`_ ``:`` `Stmt`_ ``...`` | `ConstCase `__ | | can only occur as child of a ``SwitchStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``default :`` `Stmt`_ ``...`` | `DefaultCase `__ | | can only occur as child of a ``SwitchStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| Statement syntax | CodeQL class | Superclasses | Remarks | ++============================================================================+===========================================================================================================================================================+=================================+============================================+ +| ``;`` | `EmptyStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| `Expr`_ ``;`` | `ExprStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``{`` `Stmt`_ ``... }`` | `Block `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``if (`` `Expr`_ ``)`` `Stmt`_ ``else`` `Stmt`_ | `IfStmt `__ | `ConditionalStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``if (`` `Expr`_ ``)`` `Stmt`_ | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``while (`` `Expr`_ ``)`` `Stmt`_ | `WhileStmt `__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``do`` `Stmt`_ ``while (`` `Expr`_ ``)`` | `DoStmt `__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``for (`` `Expr`_ ``;`` `Expr`_ ``;`` `Expr`_ ``)`` `Stmt`_ | `ForStmt `__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``for (`` `VarAccess`_ ``:`` `Expr`_ ``)`` `Stmt`_ | `EnhancedForStmt `__ | `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``switch (`` `Expr`_ ``) {`` `SwitchCase`_ ``... }`` | `SwitchStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``try {`` `Stmt`_ ``... } finally {`` `Stmt`_ ``... }`` | `TryStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``return`` `Expr`_ ``;`` | `ReturnStmt `__ | | | ++----------------------------------------------------------------------------+ | | | +| ``return ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``throw`` `Expr`_ ``;`` | `ThrowStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``break ;`` | `BreakStmt `__ | `JumpStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``break label ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``continue ;`` | `ContinueStmt `__ | `JumpStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``continue label ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``label :`` `Stmt`_ | `LabeledStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``synchronized (`` `Expr`_ ``)`` `Stmt`_ | `SynchronizedStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``assert`` `Expr`_ ``:`` `Expr`_ ``;`` | `AssertStmt `__ | | | ++----------------------------------------------------------------------------+ | | | +| ``assert`` `Expr`_ ``;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| `TypeAccess`_ ``name ;`` | `LocalVariableDeclStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``class name {`` `Member`_ ``... } ;`` | `LocalClassDeclStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``this (`` `Expr`_ ``, ... ) ;`` | `ThisConstructorInvocationStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``super (`` `Expr`_ ``, ... ) ;`` | `SuperConstructorInvocationStmt `__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``catch (`` `TypeAccess`_ ``name ) {`` `Stmt`_ ``... }`` | `CatchClause `__ | | can only occur as child of a `TryStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``case`` `Literal`_ ``:`` `Stmt`_ ``...`` | `ConstCase `__ | | can only occur as child of a `SwitchStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``default :`` `Stmt`_ ``...`` | `DefaultCase `__ | | can only occur as child of a `SwitchStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ Expression classes ------------------ @@ -88,130 +82,130 @@ Literals All classes in this subsection are subclasses of `Literal `__. -+---------------------------+--------------------------+ -| Expression syntax example | CodeQL class | -+===========================+==========================+ -| ``true`` | ``BooleanLiteral`` | -+---------------------------+--------------------------+ -| ``23`` | ``IntegerLiteral`` | -+---------------------------+--------------------------+ -| ``23l`` | ``LongLiteral`` | -+---------------------------+--------------------------+ -| ``4.2f`` | ``FloatingPointLiteral`` | -+---------------------------+--------------------------+ -| ``4.2`` | ``DoubleLiteral`` | -+---------------------------+--------------------------+ -| ``'a'`` | ``CharacterLiteral`` | -+---------------------------+--------------------------+ -| ``"Hello"`` | ``StringLiteral`` | -+---------------------------+--------------------------+ -| ``null`` | ``NullLiteral`` | -+---------------------------+--------------------------+ ++---------------------------+-------------------------+ +| Expression syntax example | CodeQL class | ++===========================+=========================+ +| ``true`` | `BooleanLiteral`_ | ++---------------------------+-------------------------+ +| ``23`` | `IntegerLiteral`_ | ++---------------------------+-------------------------+ +| ``23l`` | `LongLiteral`_ | ++---------------------------+-------------------------+ +| ``4.2f`` | `FloatingPointLiteral`_ | ++---------------------------+-------------------------+ +| ``4.2`` | `DoubleLiteral`_ | ++---------------------------+-------------------------+ +| ``'a'`` | `CharacterLiteral`_ | ++---------------------------+-------------------------+ +| ``"Hello"`` | `StringLiteral`_ | ++---------------------------+-------------------------+ +| ``null`` | `NullLiteral`_ | ++---------------------------+-------------------------+ Unary expressions ~~~~~~~~~~~~~~~~~ All classes in this subsection are subclasses of `UnaryExpr `__. -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| Expression syntax example | CodeQL class | Superclasses | Remarks | -+===========================+=================+=====================+===================================================+ -| ``x++`` | ``PostIncExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``x--`` | ``PostDecExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``++x`` | ``PreIncExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``--x`` | ``PreDecExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``~x`` | ``BitNotExpr`` | ``BitwiseExpr`` | see below for other subclasses of ``BitwiseExpr`` | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``-x`` | ``MinusExpr`` | | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``+x`` | ``PlusExpr`` | | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``!x`` | ``LogNotExpr`` | ``LogicExpr`` | see below for other subclasses of ``LogicExpr`` | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ ++-------------------+----------------+--------------------+--------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | Remarks | ++===================+================+====================+==================================================+ +| `Expr`_\ ``++`` | `PostIncExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| `Expr`_\ ``--`` | `PostDecExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``++``\ `Expr`_ | `PreIncExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``--``\ `Expr`_ | `PreDecExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``~``\ `Expr`_ | `BitNotExpr`_ | `BitwiseExpr`_ | see below for other subclasses of `BitwiseExpr`_ | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``-``\ `Expr`_ | `MinusExpr`_ | | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``+``\ `Expr`_ | `PlusExpr`_ | | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``!``\ `Expr`_ | `LogNotExpr`_ | `LogicExpr`_ | see below for other subclasses of `LogicExpr`_ | ++-------------------+----------------+--------------------+--------------------------------------------------+ Binary expressions ~~~~~~~~~~~~~~~~~~ All classes in this subsection are subclasses of `BinaryExpr `__. -+---------------------------+--------------------+--------------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+====================+====================+ -| ``x * y`` | ``MulExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x / y`` | ``DivExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x % y`` | ``RemExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x + y`` | ``AddExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x - y`` | ``SubExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x << y`` | ``LShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x >> y`` | ``RShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x >>> y`` | ``URShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x && y`` | ``AndLogicalExpr`` | ``LogicExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x || y`` | ``OrLogicalExpr`` | ``LogicExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x < y`` | ``LTExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x > y`` | ``GTExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x <= y`` | ``LEExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x >= y`` | ``GEExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x == y`` | ``EQExpr`` | ``EqualityTest`` | -+---------------------------+--------------------+--------------------+ -| ``x != y`` | ``NEExpr`` | ``EqualityTest`` | -+---------------------------+--------------------+--------------------+ -| ``x & y`` | ``AndBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x | y`` | ``OrBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x ^ y`` | ``XorBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ ++-------------------------+-------------------+-------------------+ +| Expression syntax | CodeQL class | Superclasses | ++=========================+===================+===================+ +| `Expr`_ ``*`` `Expr`_ | `MulExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``/`` `Expr`_ | `DivExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``%`` `Expr`_ | `RemExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``+`` `Expr`_ | `AddExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``-`` `Expr`_ | `SubExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<<`` `Expr`_ | `LShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>>`` `Expr`_ | `RShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>>>`` `Expr`_ | `URShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``&&`` `Expr`_ | `AndLogicalExpr`_ | `LogicExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``||`` `Expr`_ | `OrLogicalExpr`_ | `LogicExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<`` `Expr`_ | `LTExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>`` `Expr`_ | `GTExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<=`` `Expr`_ | `LEExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>=`` `Expr`_ | `GEExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``==`` `Expr`_ | `EQExpr`_ | `EqualityTest`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``!=`` `Expr`_ | `NEExpr`_ | `EqualityTest`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``&`` `Expr`_ | `AndBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``|`` `Expr`_ | `OrBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``^`` `Expr`_ | `XorBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ Assignment expressions ~~~~~~~~~~~~~~~~~~~~~~ All classes in this table are subclasses of `Assignment `__. -+---------------------------+-----------------------+--------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+=======================+==============+ -| ``x = y`` | ``AssignExpr`` | | -+---------------------------+-----------------------+--------------+ -| ``x += y`` | ``AssignAddExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x -= y`` | ``AssignSubExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x *= y`` | ``AssignMulExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x /= y`` | ``AssignDivExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x %= y`` | ``AssignRemExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x &= y`` | ``AssignAndExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x |= y`` | ``AssignOrExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x ^= y`` | ``AssignXorExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x <<= y`` | ``AssignLShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x >>= y`` | ``AssignRShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x >>>= y`` | ``AssignURShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ ++--------------------------+----------------------+--------------+ +| Expression syntax | CodeQL class | Superclasses | ++==========================+======================+==============+ +| `Expr`_ ``=`` `Expr`_ | `AssignExpr`_ | | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``+=`` `Expr`_ | `AssignAddExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``-=`` `Expr`_ | `AssignSubExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``*=`` `Expr`_ | `AssignMulExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``/=`` `Expr`_ | `AssignDivExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``%=`` `Expr`_ | `AssignRemExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``&=`` `Expr`_ | `AssignAndExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``|=`` `Expr`_ | `AssignOrExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``^=`` `Expr`_ | `AssignXorExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``<<=`` `Expr`_ | `AssignLShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``>>=`` `Expr`_ | `AssignRShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``>>>=`` `Expr`_ | `AssignURShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ Accesses ~~~~~~~~ @@ -246,7 +240,7 @@ Accesses | ``? super Double`` | | +--------------------------------------+-------------------------------------------------------------------------------------------------------------------------+ -A ``VarAccess`` that refers to a field is a `FieldAccess `__. +A `VarAccess `__ that refers to a field is a `FieldAccess `__. Miscellaneous ~~~~~~~~~~~~~ @@ -270,7 +264,82 @@ Miscellaneous +------------------------------------------------------------------+ + + | ``new int[] { 23, 42 }`` | | | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ -| ``{ 23, 42 }`` | `ArrayInit `__ | can only appear as an initializer or as a child of an ``ArrayCreationExpr`` | +| ``{ 23, 42 }`` | `ArrayInit `__ | can only appear as an initializer or as a child of an `ArrayCreationExpr`_ | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ | ``@Annot(key=val)`` | `Annotation `__ |   | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst + +.. _Expr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Expr.html +.. _Stmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html +.. _VarAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html +.. _SwitchCase: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchCase.html +.. _TypeAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html +.. _Member: https://help.semmle.com/qldoc/java/semmle/code/java/Member.qll/type.Member$Member.html +.. _Literal: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html +.. _ConditionalStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html +.. _LoopStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html +.. _JumpStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$JumpStmt.html +.. _TryStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html +.. _SwitchStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html +.. _BooleanLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BooleanLiteral.html +.. _IntegerLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$IntegerLiteral.html +.. _LongLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LongLiteral.html +.. _FloatingPointLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$FloatingPointLiteral.html +.. _DoubleLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$DoubleLiteral.html +.. _CharacterLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$CharacterLiteral.html +.. _StringLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$StringLiteral.html +.. _NullLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$NullLiteral.html +.. _PostIncExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PostIncExpr.html +.. _PostDecExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PostDecExpr.html +.. _PreIncExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PreIncExpr.html +.. _PreDecExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PreDecExpr.html +.. _BitNotExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitNotExpr.html +.. _MinusExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$MinusExpr.html +.. _PlusExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PlusExpr.html +.. _LogNotExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogNotExpr.html +.. _UnaryAssignExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html +.. _BitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html +.. _LogicExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html +.. _MulExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$MulExpr.html +.. _DivExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$DivExpr.html +.. _RemExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$RemExpr.html +.. _AddExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AddExpr.html +.. _SubExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$SubExpr.html +.. _LShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LShiftExpr.html +.. _RShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$RShiftExpr.html +.. _URShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$URShiftExpr.html +.. _AndLogicalExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AndLogicalExpr.html +.. _OrLogicalExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$OrLogicalExpr.html +.. _LTExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LTExpr.html +.. _GTExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$GTExpr.html +.. _LEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LEExpr.html +.. _GEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$GEExpr.html +.. _EQExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$EQExpr.html +.. _NEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$NEExpr.html +.. _AndBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AndBitwiseExpr.html +.. _OrBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$OrBitwiseExpr.html +.. _XorBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$XorBitwiseExpr.html +.. _LogicExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html +.. _ComparisonExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html +.. _EqualityTest: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$EqualityTest.html +.. _BitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html +.. _AssignExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignExpr.html +.. _AssignAddExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignAddExpr.html +.. _AssignSubExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignSubExpr.html +.. _AssignMulExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignMulExpr.html +.. _AssignDivExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignDivExpr.html +.. _AssignRemExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignRemExpr.html +.. _AssignAndExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignAndExpr.html +.. _AssignOrExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignOrExpr.html +.. _AssignXorExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignXorExpr.html +.. _AssignLShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignLShiftExpr.html +.. _AssignRShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignRShiftExpr.html +.. _AssignURShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignURShiftExpr.html +.. _AssignOp: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html +.. _ArrayCreationExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ArrayCreationExpr.html diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index 6f7874c772f..f55cf3b0524 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -78,7 +78,7 @@ We can use the ``Callable`` class to write a query that finds methods that are n where not exists(Callable caller | caller.polyCalls(callee)) select callee -➤ `See this in the query console on LGTM.com `__. This simple query typically returns a large number of results. +➤ `See this in the query console on LGTM.com `__. This simple query typically returns a large number of results. .. pull-quote:: @@ -97,7 +97,7 @@ Running this query on a typical Java project results in lots of hits in the Java callee.getCompilationUnit().fromSource() select callee, "Not called." -➤ `See this in the query console on LGTM.com `__. This change reduces the number of results returned for most projects. +➤ `See this in the query console on LGTM.com `__. This change reduces the number of results returned for most projects. We might also notice several unused methods with the somewhat strange name ````: these are class initializers; while they are not explicitly called anywhere in the code, they are called implicitly whenever the surrounding class is loaded. Hence it makes sense to exclude them from our query. While we are at it, we can also exclude finalizers, which are similarly invoked implicitly: @@ -111,7 +111,7 @@ We might also notice several unused methods with the somewhat strange name ``") and not callee.hasName("finalize") select callee, "Not called." -➤ `See this in the query console on LGTM.com `__. This also reduces the number of results returned by most projects. +➤ `See this in the query console on LGTM.com `__. This also reduces the number of results returned by most projects. We may also want to exclude public methods from our query, since they may be external API entry points: @@ -126,7 +126,7 @@ We may also want to exclude public methods from our query, since they may be ext not callee.isPublic() select callee, "Not called." -➤ `See this in the query console on LGTM.com `__. This should have a more noticeable effect on the number of results returned. +➤ `See this in the query console on LGTM.com `__. This should have a more noticeable effect on the number of results returned. A further special case is non-public default constructors: in the singleton pattern, for example, a class is provided with private empty default constructor to prevent it from being instantiated. Since the very purpose of such constructors is their not being called, they should not be flagged up: @@ -142,9 +142,9 @@ A further special case is non-public default constructors: in the singleton patt not callee.(Constructor).getNumberOfParameters() = 0 select callee, "Not called." -➤ `See this in the query console on LGTM.com `__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. +➤ `See this in the query console on LGTM.com `__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. -Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The QL Java library has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: +Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The CodeQL library for Java has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: .. code-block:: ql @@ -159,11 +159,10 @@ Finally, on many Java projects there are methods that are invoked indirectly by not callee.getDeclaringType() instanceof TestClass select callee, "Not called." -➤ `See this in the query console on LGTM.com `__. This should give a further reduction in the number of results returned. +➤ `See this in the query console on LGTM.com `__. This should give a further reduction in the number of results returned. Further reading --------------- -- Find out how to query metadata and white space: :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/dataflow.rst b/docs/language/learn-ql/java/dataflow.rst index 60107f62195..b8776548de9 100644 --- a/docs/language/learn-ql/java/dataflow.rst +++ b/docs/language/learn-ql/java/dataflow.rst @@ -257,13 +257,6 @@ Exercise 3: Write a class that represents flow sources from ``java.lang.System.g Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from ``getenv`` to ``java.net.URL``. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Try the worked examples in these articles: :doc:`Navigating the call graph ` and :doc:`Working with source locations `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. - Answers ------- @@ -361,3 +354,11 @@ Exercise 4 from DataFlow::Node src, DataFlow::Node sink, GetenvToURLConfiguration config where config.hasFlow(src, sink) select src, "This environment variable constructs a URL $@.", sink, "here" + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index 24fb943ace5..e1af4ad4f2d 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -26,7 +26,7 @@ If ``l`` is bigger than 2\ :sup:`31`\ - 1 (the largest positive value of type `` All primitive numeric types have a maximum value, beyond which they will wrap around to their lowest possible value (called an "overflow"). For ``int``, this maximum value is 2\ :sup:`31`\ - 1. Type ``long`` can accommodate larger values up to a maximum of 2\ :sup:`63`\ - 1. In this example, this means that ``l`` can take on a value that is higher than the maximum for type ``int``; ``i`` will never be able to reach this value, instead overflowing and returning to a low value. -We're going to develop a query that finds code that looks like it might exhibit this kind of behavior. We'll be using several of the standard library classes for representing statements and functions. For a full list, see :doc:`Classes for working with Java code `. +We're going to develop a query that finds code that looks like it might exhibit this kind of behavior. We'll be using several of the standard library classes for representing statements and functions. For a full list, see :doc:`Abstract syntax tree classes for working with Java programs `. Initial query ------------- @@ -42,7 +42,7 @@ We'll start by writing a query that finds less-than expressions (CodeQL class `` expr.getRightOperand().getType().hasName("long") select expr -➤ `See this in the query console on LGTM.com `__. This query usually finds results on most projects. +➤ `See this in the query console on LGTM.com `__. This query usually finds results on most projects. Notice that we use the predicate ``getType`` (available on all subclasses of ``Expr``) to determine the type of the operands. Types, in turn, define the ``hasName`` predicate, which allows us to identify the primitive types ``int`` and ``long``. As it stands, this query finds *all* less-than expressions comparing ``int`` and ``long``, but in fact we are only interested in comparisons that are part of a loop condition. Also, we want to filter out comparisons where either operand is constant, since these are less likely to be real bugs. The revised query looks like this: @@ -57,7 +57,7 @@ Notice that we use the predicate ``getType`` (available on all subclasses of ``E not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found. +➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found. The class ``LoopStmt`` is a common superclass of all loops, including, in particular, ``for`` loops as in our example above. While different kinds of loops have different syntax, they all have a loop condition, which can be accessed through predicate ``getCondition``. We use the reflexive transitive closure operator ``*`` applied to the ``getAChildExpr`` predicate to express the requirement that ``expr`` should be nested inside the loop condition. In particular, it can be the loop condition itself. @@ -120,11 +120,10 @@ Now we rewrite our query to make use of these new classes: not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See the full query in the query console on LGTM.com `__. +➤ `See the full query in the query console on LGTM.com `__. Further reading --------------- -- Have a look at some of the other articles in this section: :doc:`Java types `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 8fd21c2d0c2..3d4f5920e72 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -1,7 +1,7 @@ CodeQL library for Java ======================= -When you're analyzing a Java program in {{ site.data.variables.product.prodname_dotcom }}, you can make use of the large collection of classes in the CodeQL library for Java. +When you're analyzing a Java program, you can make use of the large collection of classes in the CodeQL library for Java. About the CodeQL library for Java --------------------------------- @@ -49,7 +49,7 @@ Types Class ``Type`` has a number of subclasses for representing different kinds of types: -- ``PrimitiveType`` represents a `primitive type `__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``; QL also classifies ``void`` and ```` (the type of the ``null`` literal) as primitive types. +- ``PrimitiveType`` represents a `primitive type `__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``; QL also classifies ``void`` and ```` (the type of the ``null`` literal) as primitive types. - ``RefType`` represents a reference (that is, non-primitive) type; it in turn has several subclasses: - ``Class`` represents a Java class. @@ -68,7 +68,7 @@ For example, the following query finds all variables of type ``int`` in the prog pt.hasName("int") select v -➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``. +➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``. Reference types are also categorized according to their declaration scope: @@ -85,15 +85,15 @@ For instance, this query finds all top-level types whose name is not the same as where tl.getName() != tl.getCompilationUnit().getName() select tl -➤ `See this in the query console on LGTM.com `__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. +➤ `See this in the query console on LGTM.com `__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. Several more specialized classes are available as well: - ``TopLevelClass`` represents a class declared at the top-level of a compilation unit. -- ``NestedClass`` represents `a class declared inside another type `__, such as: +- ``NestedClass`` represents `a class declared inside another type `__, such as: - - A ``LocalClass``, which is `a class declared inside a method or constructor `__. - - An ``AnonymousClass``, which is an `anonymous class `__. + - A ``LocalClass``, which is `a class declared inside a method or constructor `__. + - An ``AnonymousClass``, which is an `anonymous class `__. Finally, the library also has a number of singleton classes that wrap frequently used Java standard library classes: ``TypeObject``, ``TypeCloneable``, ``TypeRuntime``, ``TypeSerializable``, ``TypeString``, ``TypeSystem`` and ``TypeClass``. Each CodeQL class represents the standard Java class suggested by its name. @@ -107,7 +107,7 @@ As an example, we can write a query that finds all nested classes that directly where nc.getASupertype() instanceof TypeObject select nc -➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. +➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. Generics ~~~~~~~~ @@ -141,7 +141,7 @@ For instance, we could use the following query to find all parameterized instanc pt.getSourceDeclaration() = map select pt -➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. In general, generic types may restrict which types a type parameter can be bound to. For instance, a type of maps from strings to numbers could be declared as follows: @@ -164,7 +164,7 @@ As an example, the following query finds all type variables with type bound ``Nu tb.getType().hasQualifiedName("java.lang", "Number") select tv -➤ `See this in the query console on LGTM.com `__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *gradle/gradle* and *hibernate/hibernate-orm* projects all contained examples of this pattern. +➤ `See this in the query console on LGTM.com `__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *hibernate/hibernate-orm* and *apache/hadoop* projects all contained examples of this pattern. For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In the CodeQL libraries, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``: @@ -177,7 +177,7 @@ For dealing with legacy code that is unaware of generics, every generic type has rt.getSourceDeclaration().hasQualifiedName("java.util", "Map") select v -➤ `See this in the query console on LGTM.com `__. Many projects have variables of raw type ``Map``. +➤ `See this in the query console on LGTM.com `__. Many projects have variables of raw type ``Map``. For example, in the following code snippet this query would find ``m1``, but not ``m2``: @@ -186,7 +186,7 @@ For example, in the following code snippet this query would find ``m1``, but not Map m1 = new HashMap(); Map m2 = new HashMap(); -Finally, variables can be declared to be of a `wildcard type `__: +Finally, variables can be declared to be of a `wildcard type `__: .. code-block:: java @@ -201,7 +201,7 @@ For more information on working with types, see the :doc:`article on Java types Variables ~~~~~~~~~ -Class ``Variable`` represents a variable `in the Java sense `__, which is either a member field of a class (whether static or not), or a local variable, or a parameter. Consequently, there are three subclasses catering to these special cases: +Class ``Variable`` represents a variable `in the Java sense `__, which is either a member field of a class (whether static or not), or a local variable, or a parameter. Consequently, there are three subclasses catering to these special cases: - ``Field`` represents a Java field. - ``LocalVariableDecl`` represents a local variable. @@ -210,7 +210,7 @@ Class ``Variable`` represents a variable `in the Java sense `. +Classes in this category represent abstract syntax tree (AST) nodes, that is, statements (class ``Stmt``) and expressions (class ``Expr``). For a full list of expression and statement types available in the standard QL library, see :doc:`Abstract syntax tree classes for working with Java programs `. Both ``Expr`` and ``Stmt`` provide member predicates for exploring the abstract syntax tree of a program: @@ -228,7 +228,7 @@ For example, the following query finds all expressions whose parents are ``retur where e.getParent() instanceof ReturnStmt select e -➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``return`` statements with child statements. +➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``return`` statements with child expressions. Therefore, if the program contains a return statement ``return x + y;``, this query will return ``x + y``. @@ -242,7 +242,7 @@ As another example, the following query finds statements whose parent is an ``if where s.getParent() instanceof IfStmt select s -➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``if`` statements with child statements. +➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``if`` statements with child statements. This query will find both ``then`` branches and ``else`` branches of all ``if`` statements in the program. @@ -256,7 +256,7 @@ Finally, here is a query that finds method bodies: where s.getParent() instanceof Method select s -➤ `See this in the query console on LGTM.com `__. Most projects have many method bodies. +➤ `See this in the query console on LGTM.com `__. Most projects have many method bodies. As these examples show, the parent node of an expression is not always an expression: it may also be a statement, for example, an ``IfStmt``. Similarly, the parent node of a statement is not always a statement: it may also be a method or a constructor. To capture this, the QL Java library provides two abstract class ``ExprParent`` and ``StmtParent``, the former representing any node that may be the parent node of an expression, and the latter any node that may be the parent node of a statement. @@ -265,7 +265,7 @@ For more information on working with AST classes, see the :doc:`article on overf Metadata -------- -Java programs have several kinds of metadata, in addition to the program code proper. In particular, there are `annotations `__ and `Javadoc `__ comments. Since this metadata is interesting both for enhancing code analysis and as an analysis subject in its own right, the QL library defines classes for accessing it. +Java programs have several kinds of metadata, in addition to the program code proper. In particular, there are `annotations `__ and `Javadoc `__ comments. Since this metadata is interesting both for enhancing code analysis and as an analysis subject in its own right, the QL library defines classes for accessing it. For annotations, class ``Annotatable`` is a superclass of all program elements that can be annotated. This includes packages, reference types, fields, methods, constructors, and local variable declarations. For every such element, its predicate ``getAnAnnotation`` allows you to retrieve any annotations the element may have. For example, the following query finds all annotations on constructors: @@ -276,7 +276,7 @@ For annotations, class ``Annotatable`` is a superclass of all program elements t from Constructor c select c.getAnAnnotation() -➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. These annotations are represented by class ``Annotation``. An annotation is simply an expression whose type is an ``AnnotationType``. For example, you can amend this query so that it only reports deprecated constructors: @@ -290,7 +290,7 @@ These annotations are represented by class ``Annotation``. An annotation is simp anntp.hasQualifiedName("java.lang", "Deprecated") select ann -➤ `See this in the query console on LGTM.com `__. Only constructors with the ``@deprecated`` annotation are reported this time. +➤ `See this in the query console on LGTM.com `__. Only constructors with the ``@Deprecated`` annotation are reported this time. For more information on working with annotations, see the :doc:`article on annotations `. @@ -305,7 +305,7 @@ For Javadoc, class ``Element`` has a member predicate ``getDoc`` that returns a jdoc = f.getDoc().getJavadoc() select jdoc -➤ `See this in the query console on LGTM.com `__. You can see this pattern in many projects. +➤ `See this in the query console on LGTM.com `__. You can see this pattern in many projects. Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocElement`` nodes, which can be traversed using member predicates ``getAChild`` and ``getParent``. For instance, you could edit the query so that it finds all ``@author`` tags in Javadoc comments on private fields: @@ -319,7 +319,7 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle at.getParent+() = jdoc select at -➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. .. pull-quote:: @@ -336,7 +336,7 @@ The standard QL Java library provides extensive support for computing metrics on Altogether, there are six such classes: ``MetricElement``, ``MetricPackage``, ``MetricRefType``, ``MetricField``, ``MetricCallable``, and ``MetricStmt``. The corresponding element classes each provide a member predicate ``getMetrics`` that can be used to obtain an instance of the delegate class, on which metric computations can then be performed. -For example, the following query finds methods with a `cyclomatic complexity `__ greater than 40: +For example, the following query finds methods with a `cyclomatic complexity `__ greater than 40: .. code-block:: ql @@ -347,7 +347,7 @@ For example, the following query finds methods with a `cyclomatic complexity 40 select m -➤ `See this in the query console on LGTM.com `__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. +➤ `See this in the query console on LGTM.com `__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. Call graph ---------- @@ -367,7 +367,7 @@ We can use predicate ``Call.getCallee`` to find out which method or constructor m.hasName("println") select c -➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all include many calls to methods of this name. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all include many calls to methods of this name. Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So we can find methods and constructors that are never called using this query: @@ -379,13 +379,12 @@ Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So where not exists(c.getAReference()) select c -➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph `. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph `. For more information about callables and calls, see the :doc:`article on the call graph `. Further reading --------------- -- Experiment with the worked examples in the CodeQL for Java articles: :doc:`Java types `, :doc:`Overflow-prone comparisons in Java `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc ` and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/javadoc.rst b/docs/language/learn-ql/java/javadoc.rst index 85981b4bd59..1097d93c826 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -147,7 +147,7 @@ Now we can write a query for finding all callables ``c`` and ``@throws`` tags `` not mayThrow(c, exn) select tt, "Spurious @throws tag." -➤ `See this in the query console on LGTM.com `__. This finds several results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com `__. This finds several results in the LGTM.com demo projects. Improvements ~~~~~~~~~~~~ @@ -214,13 +214,12 @@ The first case can be covered by changing ``getDocumentedException`` to use the (result.hasName(tt.getExceptionName()) and visibleIn(tt.getFile(), result)) } -➤ `See this in the query console on LGTM.com `__. This finds many fewer, more interesting results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com `__. This finds many fewer, more interesting results in the LGTM.com demo projects. Currently, ``visibleIn`` only considers single-type imports, but you could extend it with support for other kinds of imports. Further reading --------------- -- Find out how you can use the location API to define queries on whitespace: :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/ql-for-java.rst b/docs/language/learn-ql/java/ql-for-java.rst index 3b5b64dd99b..480b0078808 100644 --- a/docs/language/learn-ql/java/ql-for-java.rst +++ b/docs/language/learn-ql/java/ql-for-java.rst @@ -34,12 +34,5 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Working with source locations `: You can use the location of entities within Java code to look for potential errors. Locations allow you to deduce the presence, or absence, of white space which, in some cases, may indicate a problem. -- :doc:`Classes for working with Java code `: CodeQL has a large selection of classes for working with Java statements and expressions. +- :doc:`Abstract syntax tree classes for working with Java programs `: CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs. - -Further reading ---------------- - -- For examples of how to query common Java elements, see the `Java cookbook `__. -- For the queries used in LGTM, display a `Java query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for Java see the `CodeQL library for Java `__. diff --git a/docs/language/learn-ql/java/source-locations.rst b/docs/language/learn-ql/java/source-locations.rst index 7d3506b3923..3ab90906d99 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -54,17 +54,17 @@ In our example, the expression statement starts at line 5, column 3 (the first t Class ``File`` defines these member predicates: -- ``getFullName`` returns the fully qualified name of the file. +- ``getAbsolutePath`` returns the fully qualified name of the file. - ``getRelativePath`` returns the path of the file relative to the base directory of the source code. - ``getExtension`` returns the extension of the file. -- ``getShortName`` returns the base name of the file, without its extension. +- ``getStem`` returns the base name of the file, without its extension. In our example, assume file ``A.java`` is located in directory ``/home/testuser/code/pkg``, where ``/home/testuser/code`` is the base directory of the program being analyzed. Then, a ``File`` object for ``A.java`` returns: -- ``getFullName`` is ``/home/testuser/code/pkg/A.java``. +- ``getAbsolutePath`` is ``/home/testuser/code/pkg/A.java``. - ``getRelativePath`` is ``pkg/A.java``. - ``getExtension`` is ``java``. -- ``getShortName`` is ``A``. +- ``getStem`` is ``A``. Determining white space around an operator ------------------------------------------ @@ -110,7 +110,7 @@ Here's a first version of our query: wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com `__. This query is likely to find results on most projects. +➤ `See this in the query console on LGTM.com `__. This query is likely to find results on most projects. The first conjunct of the ``where`` clause restricts ``inner`` to be an operand of ``outer``, the second conjunct binds ``wsinner`` and ``wsouter``, while the last conjunct selects the suspicious cases. @@ -141,9 +141,9 @@ Note that our predicate ``operatorWS`` computes the **total** amount of white sp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com `__. Any results will be refined by our changes to the query. +➤ `See this in the query console on LGTM.com `__. Any results will be refined by our changes to the query. -Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive.To exclude these cases, let us define a new class identifying binary expressions with an associative operator: +Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive. To exclude these cases, let us define a new class identifying binary expressions with an associative operator: .. code-block:: ql @@ -173,9 +173,9 @@ Now we can extend our query to discard results where the outer and the inner exp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com `__. +➤ `See this in the query console on LGTM.com `__. -Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase `__: +Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase `__: .. code-block:: java @@ -186,5 +186,5 @@ Whitespace suggests that the programmer meant to toggle ``i`` between zero and o Further reading --------------- -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index 3cdafa8389a..a8a6c17f0cb 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -32,7 +32,7 @@ To determine ancestor types (including immediate super types, and also *their* s where B.hasName("B") select B.getASupertype+() -➤ `See this in the query console on LGTM.com `__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. +➤ `See this in the query console on LGTM.com `__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. .. pull-quote:: @@ -78,7 +78,7 @@ This recipe is not too difficult to translate into a query: target.getElementType().(RefType).getASupertype+() = source.getElementType() select ce, "Potentially problematic array downcast." -➤ `See this in the query console on LGTM.com `__. Many projects return results for this query. +➤ `See this in the query console on LGTM.com `__. Many projects return results for this query. Note that by casting ``target.getElementType()`` to a ``RefType``, we eliminate all cases where the element type is a primitive type, that is, ``target`` is an array of primitive type: the problem we are looking for cannot arise in that case. Unlike in Java, a cast in QL never fails: if an expression cannot be cast to the desired type, it is simply excluded from the query results, which is exactly what we want. @@ -97,7 +97,7 @@ In code that does not use generics, this method is often used in the following w Here, ``l`` has the raw type ``List``, so ``l.toArray`` has return type ``Object[]``, independent of the type of its argument array. Hence the cast goes from ``Object[]`` to ``A[]`` and will be flagged as problematic by our query, although at runtime this cast can never go wrong. -To identify these cases, we can create two CodeQL classes that represent, respectively, the ``Collection.toArray`` class, and calls to this method or any method that overrides it: +To identify these cases, we can create two CodeQL classes that represent, respectively, the ``Collection.toArray`` method, and calls to this method or any method that overrides it: .. code-block:: ql @@ -114,7 +114,7 @@ To identify these cases, we can create two CodeQL classes that represent, respec class CollectionToArrayCall extends MethodAccess { CollectionToArrayCall() { exists(CollectionToArray m | - this.getMethod().getSourceDeclaration().overrides*(m) + this.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) ) } @@ -124,7 +124,7 @@ To identify these cases, we can create two CodeQL classes that represent, respec } } -Notice the use of ``getSourceDeclaration`` and ``overrides`` in the constructor of ``CollectionToArrayCall``: we want to find calls to ``Collection.toArray`` and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call ``l.toArray`` resolves to method ``toArray`` in the raw class ``ArrayList``. Its source declaration is method\ ``toArray`` in the generic class ``ArrayList``, which overrides ``AbstractCollection.toArray``, which in turn overrides ``Collection.toArray``. +Notice the use of ``getSourceDeclaration`` and ``overridesOrInstantiates`` in the constructor of ``CollectionToArrayCall``: we want to find calls to ``Collection.toArray`` and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call ``l.toArray`` resolves to method ``toArray`` in the raw class ``ArrayList``. Its source declaration is ``toArray`` in the generic class ``ArrayList``, which overrides ``AbstractCollection.toArray``, which in turn overrides ``Collection.toArray``, which is an instantiation of ``Collection.toArray`` (since the type parameter ``T`` in the overridden method belongs to ``ArrayList`` and is an instantiation of the type parameter belonging to ``Collection``). Using these new classes we can extend our query to exclude calls to ``toArray`` on an argument of type ``A[]`` which are then cast to ``A[]``: @@ -141,14 +141,14 @@ Using these new classes we can extend our query to exclude calls to ``toArray`` not ce.getExpr().(CollectionToArrayCall).getActualReturnType() = target select ce, "Potentially problematic array downcast." -➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found by this improved query. +➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found by this improved query. Example: Finding mismatched contains checks ------------------------------------------- We'll now develop a query that finds uses of ``Collection.contains`` where the type of the queried element is unrelated to the element type of the collection, which guarantees that the test will always return ``false``. -For example, `Apache Zookeeper `__ used to have a snippet of code similar to the following in class ``QuorumPeerConfig``: +For example, `Apache Zookeeper `__ used to have a snippet of code similar to the following in class ``QuorumPeerConfig``: .. code-block:: java @@ -267,7 +267,7 @@ Now we are ready to write a first version of our query: not haveCommonDescendant(collEltType, argType) select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See this in the query console on LGTM.com `__. +➤ `See this in the query console on LGTM.com `__. Improvements ~~~~~~~~~~~~ @@ -294,11 +294,10 @@ Adding these three improvements, our final query becomes: not argType.hasName("") select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See the full query in the query console on LGTM.com `__. +➤ `See the full query in the query console on LGTM.com `__. Further reading --------------- -- Take a look at some of the other articles in this section: :doc:`Overflow-prone comparisons in Java `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/ast-class-reference.rst b/docs/language/learn-ql/javascript/ast-class-reference.rst index f0a7f88fc17..b041302bf86 100644 --- a/docs/language/learn-ql/javascript/ast-class-reference.rst +++ b/docs/language/learn-ql/javascript/ast-class-reference.rst @@ -1,7 +1,9 @@ -Abstract syntax tree classes for JavaScript and TypeScript -========================================================== +Abstract syntax tree classes for working with JavaScript and TypeScript programs +================================================================================ -CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. +CodeQL has a large selection of classes for representing the abstract syntax tree of JavaScript and TypeScript programs. + +.. include:: ../../reusables/abstract-syntax-tree.rst Statement classes ----------------- @@ -356,3 +358,9 @@ All classes in this table are subclasses of `Expr `__ | `YieldExpr `__ | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index a78dc116e37..727adf42172 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -142,7 +142,7 @@ Files AST nodes --------- -See also: :doc:`Abstract syntax tree classes for JavaScript and TypeScript `. +See also: :doc:`Abstract syntax tree classes for working with JavaScript and TypeScript programs `. Conversion between DataFlow and AST nodes: @@ -216,3 +216,11 @@ Troubleshooting - Compilation fails due to incompatible types? Make sure AST nodes and DataFlow nodes are not mixed up. Use `asExpr() `__ or `flow() `__ to convert. + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/dataflow.rst b/docs/language/learn-ql/javascript/dataflow.rst index 5af4fe83f2c..53eb7b425f2 100644 --- a/docs/language/learn-ql/javascript/dataflow.rst +++ b/docs/language/learn-ql/javascript/dataflow.rst @@ -468,13 +468,6 @@ Hint: array indices are properties with numeric names; you can use regular expre Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from array elements of the result of a call to the ``tagName`` argument to the ``createElement`` function. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. -- Learn about writing more precise data-flow analyses in :doc:`Using flow labels for precise data flow analysis ` - Answers ------- @@ -557,3 +550,11 @@ Exercise 4 from HardCodedTagNameConfiguration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select source, sink + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/flow-labels.rst b/docs/language/learn-ql/javascript/flow-labels.rst index ecd8dec6b29..a6e3bb322fd 100644 --- a/docs/language/learn-ql/javascript/flow-labels.rst +++ b/docs/language/learn-ql/javascript/flow-labels.rst @@ -398,6 +398,7 @@ string may be an absolute path and whether it may contain ``..`` components. Further reading --------------- -- Learn about the standard CodeQL libraries used to write queries for JavaScript in :doc:`CodeQL libraries for JavaScript `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index 65b19f2687d..32412623fc9 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -1031,6 +1031,5 @@ Predicate ``YAMLMapping.maps(key, value)`` models the key-value relation represe Further reading --------------- -- Learn about the standard CodeQL libraries used to write queries for TypeScript in :doc:`CodeQL libraries for TypeScript `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst index 672ea369479..9ffe8879bdb 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst @@ -449,6 +449,5 @@ A `LocalNamespaceName `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/ql-for-javascript.rst b/docs/language/learn-ql/javascript/ql-for-javascript.rst index 5e10e9f979d..e7f0ce5efff 100644 --- a/docs/language/learn-ql/javascript/ql-for-javascript.rst +++ b/docs/language/learn-ql/javascript/ql-for-javascript.rst @@ -26,13 +26,6 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Using type tracking for API modeling `: You can track data through an API by creating a model using the CodeQL type-tracking library for JavaScript. -- :doc:`Abstract syntax tree classes for JavaScript and TypeScript `: CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. +- :doc:`Abstract syntax tree classes for working with JavaScript and TypeScript programs `: CodeQL has a large selection of classes for representing the abstract syntax tree of JavaScript and TypeScript programs. - :doc:`Data flow cheat sheet for JavaScript `: This article describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. - -Further reading ---------------- - -- For examples of how to query common JavaScript elements, see the `JavaScript cookbook `__. -- For the queries used in LGTM, display a `JavaScript query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for JavaScript see the `CodeQL library for JavaScript `__. diff --git a/docs/language/learn-ql/javascript/type-tracking.rst b/docs/language/learn-ql/javascript/type-tracking.rst index d192d98472e..5cc223cccb7 100644 --- a/docs/language/learn-ql/javascript/type-tracking.rst +++ b/docs/language/learn-ql/javascript/type-tracking.rst @@ -493,7 +493,7 @@ Prefer data-flow configurations when: - Differentiating between different kinds of user-controlled data -- see :doc:`Using flow labels for precise data flow analysis `. - Tracking transformations of a value through generic utility functions. - Tracking values through string manipulation. -- Generating a path from source to sink -- see :doc:`constructing path queries <../writing-queries/path-queries>`. +- Generating a path from source to sink -- see :doc:`Creating path queries <../writing-queries/path-queries>`. Lastly, depending on the code base being analyzed, some alternatives to consider are: @@ -521,6 +521,5 @@ Type tracking is used in a few places in the standard libraries: Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. -- Learn about writing precise data-flow analyses in :doc:`Using flow labels for precise data flow analysis `. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/locations.rst b/docs/language/learn-ql/locations.rst index a06f428bef8..8a8b7c82869 100644 --- a/docs/language/learn-ql/locations.rst +++ b/docs/language/learn-ql/locations.rst @@ -115,3 +115,8 @@ The ``toString()`` predicate ---------------------------- All classes except those that extend primitive types, must provide a ``string toString()`` member predicate. The query compiler will complain if you don't. The uniqueness warning, noted above for locations, applies here too. + +Further reading +--------------- + +- `CodeQL repository `__ \ No newline at end of file diff --git a/docs/language/learn-ql/python/control-flow.rst b/docs/language/learn-ql/python/control-flow.rst index 9291f4dc907..4f93404865f 100644 --- a/docs/language/learn-ql/python/control-flow.rst +++ b/docs/language/learn-ql/python/control-flow.rst @@ -117,6 +117,6 @@ Example finding mutually exclusive blocks within the same function Further reading --------------- -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/functions.rst b/docs/language/learn-ql/python/functions.rst index 20e47267825..44d9771df58 100644 --- a/docs/language/learn-ql/python/functions.rst +++ b/docs/language/learn-ql/python/functions.rst @@ -3,7 +3,7 @@ Functions in Python You can use syntactic classes from the standard CodeQL library to find Python functions and identify calls to them. -These examples use the standard CodeQL class `Function `__. For more information, see ":doc:`Introducing the Python libraries `." +These examples use the standard CodeQL class `Function `__. For more information, see ":doc:`CodeQL library for Python `." Finding all functions called "get..." ------------------------------------- @@ -81,9 +81,6 @@ In a later tutorial we will see how to use the type-inference library to find ca Further reading --------------- -- ":doc:`Expressions and statements in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index d124277d0b5..d7bfb447f06 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -340,10 +340,6 @@ For more information about these classes, see ":doc:`Analyzing data flow and tra Further reading --------------- -- ":doc:`Functions in Python `" -- ":doc:`Expressions and statements in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index 8fbde0d9b35..60a3acb7fce 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -226,7 +226,6 @@ Then we can use ``Value.getACall()`` to identify calls to the ``eval`` function, Further reading --------------- -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/ql-for-python.rst b/docs/language/learn-ql/python/ql-for-python.rst index 04f6a2a0d75..0d169867c92 100644 --- a/docs/language/learn-ql/python/ql-for-python.rst +++ b/docs/language/learn-ql/python/ql-for-python.rst @@ -26,10 +26,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Pointer analysis and type inference in Python `: At runtime, each Python expression has a value with an associated type. You can learn how an expression behaves at runtime by using type-inference classes from the standard CodeQL library. - :doc:`Analyzing data flow and tracking tainted data in Python `: You can use CodeQL to track the flow of data through a Python program. Tracking user-controlled, or tainted, data is a key technique for security researchers. - -Further reading ---------------- - -- For examples of how to query common Python elements, see the `Python cookbook `__. -- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for JavaScript see the `CodeQL library for Python `__. diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 9e817d5c5c6..0cf6dd73a97 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -156,7 +156,7 @@ The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` che Tip - We have to use ``cmp.getOp(0)`` and ``cmp.getComparator(0)``\ as there is no ``cmp.getOp()`` or ``cmp.getComparator()``. The reason for this is that a ``Compare`` expression can have multiple operators. For example, the expression ``3 < x < 7`` has two operators and two comparators. You use ``cmp.getComparator(0)`` to get the first comparator (in this example the ``3``) and ``cmp.getComparator(1)`` to get the second comparator (in this example the ``7``). + We have to use ``cmp.getOp(0)`` and ``cmp.getComparator(0)``\ as there is no ``cmp.getOp()`` or ``cmp.getComparator()``. The reason for this is that a ``Compare`` expression can have multiple operators. For example, the expression ``3 < x < 7`` has two operators and two comparators. You use ``cmp.getComparator(0)`` to get the first comparator (in this example the ``x``) and ``cmp.getComparator(1)`` to get the second comparator (in this example the ``7``). Example finding duplicates in dictionary literals ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,9 +256,6 @@ Here is the relevant part of the class hierarchy: Further reading --------------- -- ":doc:`Functions in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/taint-tracking.rst b/docs/language/learn-ql/python/taint-tracking.rst index bfdae7aa4eb..03e2cc4dfc7 100644 --- a/docs/language/learn-ql/python/taint-tracking.rst +++ b/docs/language/learn-ql/python/taint-tracking.rst @@ -259,8 +259,8 @@ which defines the simplest possible taint kind class, ``HardcodedValue``, and cu Further reading --------------- -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/ql-training.rst b/docs/language/learn-ql/ql-training.rst index 5b014ca72fc..e3a9cc59135 100644 --- a/docs/language/learn-ql/ql-training.rst +++ b/docs/language/learn-ql/ql-training.rst @@ -60,5 +60,4 @@ CodeQL and variant analysis for Java Further reading ~~~~~~~~~~~~~~~ -- If you are completely new to CodeQL, look at our introductory topics in :doc:`Learning CodeQL `. -- To see examples of CodeQL queries that have been used to find security vulnerabilities and bugs in open source software projects, visit the `GitHub Security Lab website `__ and the associated `repository `__. \ No newline at end of file +- `GitHub Security Lab `__ diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 9eee078d18c..2a6ffc30d43 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -148,7 +148,7 @@ However, as written it is difficult for the optimizer to pick out the best order Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join. -Further information -------------------- +Further reading +--------------- -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index a2b1aa24804..c5743331916 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -10,19 +10,9 @@ CodeQL includes queries to find the most relevant and interesting problems for e - **Alert queries**: queries that highlight issues in specific locations in your code. - **Path queries**: queries that describe the flow of information between a source and a sink in your code. -- **Metric queries**: queries that compute statistics for your code. You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a database with the `CodeQL CLI `__, or you can contribute to the standard CodeQL queries in our `open source repository on GitHub `__. -.. pull-quote:: - - Note - - Only the results generated by alert and path queries are displayed on LGTM. - You can display the results generated by metric queries by running them against your project in the `query console on LGTM `__ or with the CodeQL `extension for VS Code `__. - You can explore the paths generated by path queries `directly in LGTM `__ and in the `Results view `__ in VS Code. - - This topic is a basic introduction to query files. You can find more information on writing queries for specific programming languages `here `__, and detailed technical information about QL in the `QL language reference `__. For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. @@ -45,17 +35,17 @@ Basic query structure where /* ... logical formula ... */ select /* ... expressions ... */ -The following sections describe the information that is typically included in a query file for alerts and metrics. Path queries are discussed in more detail in :doc:`Creating path queries `. +The following sections describe the information that is typically included in a query file for alerts. Path queries are discussed in more detail in :doc:`Creating path queries `. Query metadata ============== -Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see the :doc:`query metadata reference `. The exact metadata requirement depends on how you are going to run your query: +Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see :doc:`Metadata for CodeQL queries `. The exact metadata requirement depends on how you are going to run your query: - If you are contributing a query to the GitHub repository, please read the `query metadata style guide `__. - If you are adding a custom query to a query pack for analysis using LGTM , see `Writing custom queries to include in LGTM analysis `__. - If you are analyzing a database using the `CodeQL CLI `__, your query metadata must contain ``@kind``. -- If you are running a query in the query console on LGTM or with the CodeQL extension for VS Code, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct ``@kind`` property, as explained below. For more information, see `Using the query console `__ on LGTM.com and `Using the extension `__ in the CodeQL for VS Code help. +- If you are running a query in the query console on LGTM or with the CodeQL extension for VS Code, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct ``@kind`` property, as explained below. For more information, see `Using the query console `__ on LGTM.com and `Analyzing your projects `__ in the CodeQL for VS Code help. .. pull-quote:: @@ -65,7 +55,6 @@ Query metadata is used to identify your custom queries when they are added to th - Alert query metadata must contain ``@kind problem``. - Path query metadata must contain ``@kind path-problem``. - - Metric query metadata must contain ``@kind metric``. When you define the ``@kind`` property of a custom query you must also ensure that the rest of your query has the correct structure in order to be valid, as described below. @@ -121,13 +110,6 @@ You can modify the alert message defined in the final column of the ``select`` s Select clauses for path queries (``@kind path-problem``) are crafted to display both an alert and the source and sink of an associated path graph. For more information, see :doc:`Creating path queries `. -Select clauses for metric queries (``@kind metric``) consist of two 'columns', with the following structure:: - - select element, metric - -- ``element``: a code element that is identified by the query, which defines where the alert is displayed. -- ``metric``: the result of the metric that the query computes. - Viewing the standard CodeQL queries *********************************** @@ -150,12 +132,3 @@ Query help files **************** When you write a custom query, we also recommend that you write a query help file to explain the purpose of the query to other users. For more information, see the `Query help style guide `__ on GitHub, and the :doc:`Query help files `. - -What next? -========== - -- See the queries used in real-life variant analysis on the `GitHub Security Lab website `__. -- To learn more about writing path queries, see :doc:`Creating path queries `. -- Take a look at the `built-in queries `__ to see examples of the queries included in CodeQL. -- Explore the `query 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 `__. diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 4bdd328dca8..8bdb62ef0c2 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -189,9 +189,8 @@ The ``element`` that you select in the first column depends on the purpose of th The alert message defined in the final column in the ``select`` statement can be developed to give more detail about the alert or path found by the query using links and placeholders. For more information, see :doc:`Defining the results of a query `. -What next? -********** +Further reading +*************** -- Take a look at the path queries for `C/C++ `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of these queries. -- Explore the `query 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 `__. +- `Exploring data flow with path queries `__ +- `CodeQL repository `__ diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst index 86e7b1d4bdd..04c04e405b8 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -206,8 +206,3 @@ The included file, `ThreadUnsafeICryptoTransformOverview.qhelp -Further information -=================== - -- To learn more about contributing to the standard CodeQL queries and libraries, see our `Contributing guidelines `__ on GitHub. -- To learn more about writing custom queries, and how to format your code for clarity and consistency, see `Writing CodeQL queries `__. diff --git a/docs/language/learn-ql/writing-queries/query-metadata.rst b/docs/language/learn-ql/writing-queries/query-metadata.rst index 15edafc9993..60826439862 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -7,9 +7,8 @@ About query metadata -------------------- Any query that is run as part of an analysis includes a number of properties, known as query metadata. Metadata is included at the top of each query file as the content of a `QLDoc `__ comment. -For alerts and path queries, this metadata tells LGTM and the CodeQL `extension for VS Code `__ how to handle the query and display its results correctly. +This metadata tells LGTM and the CodeQL `extension for VS Code `__ how to handle the query and display its results correctly. It also gives other users information about what the query results mean. For further information on query metadata, see the `query metadata style guide `__ in our `open source repository `__ on GitHub. -You can also add metric queries to LGTM, but the results are not shown. To see the results of metric queries, you can run them in the query console or in `Visual Studio Code `__. .. pull-quote:: @@ -17,72 +16,36 @@ You can also add metric queries to LGTM, but the results are not shown. To see t The exact metadata requirement depends on how you are going to run your query. For more information, see the section on query metadata in :doc:`About CodeQL queries `. -Core properties ---------------- +Metadata properties +------------------- The following properties are supported by all query files: -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Description | -+=======================+===========================+==============================================================================================================================================================================================================================================================================================================================================================================+ -| ``@description`` | ```` | A sentence or short paragraph to describe the purpose of the query and *why* the result is useful or important. The description is written in plain text, and uses single quotes (``'``) to enclose code elements. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@id`` | ```` | A sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the query. Each query must have a **unique** ID. To ensure this, it may be helpful to use a fixed structure for each ID. For example, the standard LGTM queries have the following format: ``/``. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@kind`` | | ``problem`` | Identifies the query is an alert (``@kind problem``), a path (``@kind path-problem``), or a metric (``@kind metric``). For further information on these query types, see :doc:`About CodeQL queries `. | -| | | ``path-problem`` | | -| | | ``metric`` | | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@name`` | ```` | A statement that defines the label of the query. The name is written in plain text, and uses single quotes (``'``) to enclose code elements. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@tags`` | | ``correctness`` | These tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, there are also a number of more specific categories. For more information about some of the tags that are already used and what they mean, see `Query tags `__ on LGTM.com. | -| | | ``mantainability`` | | -| | | ``readability`` | | -| | | ``security`` | | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Additional properties for problem and path-problem queries ----------------------------------------------------------- - -In addition to the core properties, alert queries (``@kind problem``) and path queries (``@kind path-problem``) support the following properties: - -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Example | Notes | -+=======================+============+=======================+=====================================================================================================================================================================================================================+ -| ``@precision`` | ```` | | ``medium``   | Indicates the percentage of query results that are true positives (as opposed to false positive results). This controls how alerts for problems found by the query are displayed in client applications. | -| | | | ``high``   | | -| | | | ``very-high`` | | -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@problem.severity`` | ```` | | ``error`` | Defines the level of severity of any alerts generated by the query. This controls how alerts are displayed in client applications. | -| | | | ``warning`` | | -| | | | ``recommendation`` | | -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -Additional properties for metric queries ----------------------------------------- - -In addition to the core properties, metric queries (``@kind metric``) support the following properties: - -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Example | Notes | -+========================+==============+===================+==========================================================================================================================================================================================================+ -| ``@metricType`` | ```` | | ``file`` | Defines the code element that the query acts on. This information is used by client applications; it should match the type of result returned by the query. | -| | | | ``callable`` | | -| | | | ``package`` | | -| | | | ``project`` | | -| | | | ``reftype`` | | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@metricAggregate`` | ```` | | ``avg`` | Defines the allowable aggregations for this metric. A space separated list of the four possibilities ``sum``, ``avg``, ``min`` and ``max``. If it is not present, it defaults to ``sum avg``. | -| | | | ``sum`` | | -| | | | ``min`` | | -| | | | ``max`` | | -+--------------------+---+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@treemap.threshold`` | ```` | ``10`` | Optional, defines a metric threshold. Used with ``@treemap.warnOn`` to define a "danger area" on the metric charts displayed in client applications. | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@treemap.warnOn`` | ```` | | ``highValues`` | Optional, defines whether high or low values are dangerous. Used with ``@treemap.threshold`` to define a "danger area" on the metric charts displayed in client applications. | -| | | | ``lowValues`` | | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Property | Value | Description | ++=======================+===========================+======================================================================================================================================================================================================================================================================================================================================================+ +| ``@description`` | ```` | A sentence or short paragraph to describe the purpose of the query and *why* the result is useful or important. The description is written in plain text, and uses single quotes (``'``) to enclose code elements. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@id`` | ```` | A sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the query. Each query must have a **unique** ID. To ensure this, it may be helpful to use a fixed structure for each ID. For example, the standard LGTM queries have the following format: ``/``. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@kind`` | | ``problem`` | Identifies the query is an alert (``@kind problem``) or a path (``@kind path-problem``). For further information on these query types, see :doc:`About CodeQL queries `. | +| | | ``path-problem`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@name`` | ```` | A statement that defines the label of the query. The name is written in plain text, and uses single quotes (``'``) to enclose code elements. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@tags`` | | ``correctness`` | These tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, there are also a number of more specific categories. For more information, see the | +| | | ``maintainability`` | `Query metadata style guide `__. | +| | | ``readability`` | | +| | | ``security`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@precision`` | | ``medium``   | Indicates the percentage of query results that are true positives (as opposed to false positive results). This, along with the ``@problem.severity`` property, determines whether the results are displayed by default on LGTM. | +| | | ``high``   | | +| | | ``very-high`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@problem.severity`` | | ``error`` | Defines the level of severity of any alerts generated by the query. This, along with the ``@precision`` property, determines whether the results are displayed by default on LGTM. | +| | | ``warning`` | | +| | | ``recommendation`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Additional properties for filter queries ---------------------------------------- @@ -99,7 +62,3 @@ Here is the metadata for one of the standard Java queries: .. |image0| image:: ../../images/query-metadata.png For more examples of query metadata, see the standard CodeQL queries in our `GitHub repository `__. - - - - diff --git a/docs/language/learn-ql/writing-queries/select-statement.rst b/docs/language/learn-ql/writing-queries/select-statement.rst index 5531a958e3e..73e46d956aa 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -15,7 +15,7 @@ This topic explains how to write your select statement to generate helpful analy Overview -------- -Alert queries must have the property ``@kind problem`` defined in their metadata. For further information, see the :doc:`query metadata reference `. +Alert queries must have the property ``@kind problem`` defined in their metadata. For further information, see :doc:`Metadata for CodeQL queries `. In their most basic form, the ``select`` statement must select two 'columns': - **Element**—a code element that's identified by the query. This defines the location of the alert. @@ -27,7 +27,7 @@ If you look at some of the LGTM queries, you'll see that they can select extra e Note - An in-depth discussion of ``select`` statements for path and metric queries is not included in this topic. However, you can develop the string column of the ``select`` statement in the same way as for alert queries. For more specific information about path queries, see :doc:`Creating path queries `. + An in-depth discussion of ``select`` statements for path queries is not included in this topic. However, you can develop the string column of the ``select`` statement in the same way as for alert queries. For more specific information about path queries, see :doc:`Creating path queries `. Developing a select statement ----------------------------- @@ -105,3 +105,8 @@ The new elements added here don't need to be clickable, so we added them directl .. image:: ../../images/ql-select-statement-similarity.png :alt: Results showing the extent of similarity :class: border + +Further reading +--------------- + +- `CodeQL repository `__ \ No newline at end of file diff --git a/docs/language/ql-handbook/aliases.rst b/docs/language/ql-handbook/aliases.rst index 03bdc835a30..8b6f1c3b9be 100644 --- a/docs/language/ql-handbook/aliases.rst +++ b/docs/language/ql-handbook/aliases.rst @@ -42,6 +42,8 @@ of ``OldVersion``, you could deprecate the name ``OldVersion`` as follows:: That way both names resolve to the same module, but if you use the name ``OldVersion``, a deprecation warning is displayed. +.. _type-aliases: + Type aliases ============ diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 1446e18a4f8..782e62e63db 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -42,6 +42,76 @@ A QL program can be *evaluated* (see `Evaluation <#evaluation>`__) to produce a For a QL program to be *valid*, it must conform to a variety of conditions that are described throughout this specification; otherwise the program is said to be *invalid*. An implementation of QL must detect all invalid programs and refuse to evaluate them. +Library path +------------ + +The library path is an ordered list of directory locations. It is used +for resolving module imports (see `Module resolution <#module-resolution>`__). The library path is not strictly +speaking a core part of the QL language, since different +implementations of QL construct it in slightly different ways. Most QL +tools also allow you to explicitly specify the library path on the command line for a +particular invocation, though that is rarely done, and only +useful in very special situations. This section describes the default +construction of the library path. + +First, determine the *query directory* of the ``.ql`` file being +compiled. Starting with the directory containing the ``.ql`` file, and +walking up the directory structure, each directory is checked for a +file called ``queries.xml`` or ``qlpack.yml``. The first directory +where such a file is found is the query directory. If there is no such +directory, the directory of the ``.ql`` file itself is the query +directory. + +A ``queries.xml`` file that defines a query directory must always +contain a single top-level tag named +``queries``, which has a ``language`` attribute set to the identifier +of the active database schema (for example, ````). + +A ``qlpack.yml`` file defines a `QL pack +`__. +The content of a ``qlpack.yml`` file is described in the CodeQL CLI documentation. This file +will not be recognized when using legacy tools that are not based +on the CodeQL CLI (that is, LGTM.com, LGTM Enterprise, ODASA, CodeQL for +Eclipse, and CodeQL for Visual Studio). + +If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same +directory, the latter takes precedence (and the former is assumed to +exist for compatibility with older tooling). + +In legacy QL tools that don't recognize ``qlpack.yml`` files, the default +value of the library path for +each supported language is hard-coded. The tools contain directories within the ODASA +distribution that define the default CodeQL libraries for the selected +language. Which language to use depends on the ``language`` attribute +of the ``queries.xml`` file if not overridden with a ``--language`` +option to the ODASA CLI. + +On the other hand, the CodeQL CLI and newer tools based on it (such as +GitHub Code Scanning and the CodeQL extension for Visual Studio Code) +construct a library path using QL packs. For each QL pack +added to the library path, the QL packs named in its +``libraryPathDependencies`` will be subsequently added to the library +path, and the process continues until all packs have been +resolved. The actual library path consists of the root directories of +the selected QL packs. This process depends on a mechanism for finding +QL packs by pack name, as described in the `CodeQL CLI documentation `__. + +When the query directory contains a ``queries.xml`` file but no +``qlpack.yml``, the QL pack resolution behaves as if it defines a QL +pack with no name and a single library path dependency named +``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from +``queries.xml``. The ``github/codeql`` repository provides packs with +names following this pattern, which themselves depend on the actual +CodeQL libraries for each language. + +When the query directory contains neither a ``queries.xml`` nor +``qlpack.yml`` file, it is considered to be a QL pack with no name and +no library dependencies. This causes the library path to consist of +*only* the query directory itself. This is not generally useful, +but it suffices for running toy examples of QL code that don't +use information from the database. + Name resolution --------------- @@ -162,11 +232,10 @@ For selection identifiers (``a::b``): For qualified identifiers (``a.b``): -- Define the *current file* as the file the import directive occurs in. - -- Determine the current file's *query directory*, if any. Starting with the directory containing the current file, and walking up the directory structure, each directory is checked for a file called ``queries.xml``, containing a single top-level tag named ``queries``, which has a ``language`` attribute set to the identifier of the active database scheme (for example, ````). The closest enclosing directory is taken as the current file's query directory. - -- Build up a list of *candidate search paths*, consisting of the current file's directory, the current file's query directory (if one was determined in the previous step), and the list of directories making up the library path (in order). +- Build up a list of *candidate search paths*, consisting of the + current file's directory, then the *query directory* of the current + file, and finally each of the directories on the + `library path <#library-path>`__ (in order). - Determine the first candidate search path that has a *matching* QLL file for the import directive's qualified name. A QLL file in a candidate search path is said to match a qualified name if, starting from the candidate search path, there is a subdirectory for each successive qualifier in the qualified name, and the directory named by the final qualifier contains a file whose base name matches the qualified name's base name, with the addition of the file extension ``.qll``. The file and directory names are matched case-sensitively, regardless of whether the filesystem is case-sensitive or not. @@ -341,7 +410,7 @@ A value ``v`` is in a type ``t`` under any of the following conditions: An ordered tuple *satisfies a predicate* ``p`` under the following circumstances. If ``p`` is not a member predicate, then the tuple satisfies the predicate whenever it directly satisfies the predicate. -Otherwise, the tuple must be the tuple of a fact in the store with predicate ``q``, where ``q`` has the same root definition as ``p``. The first element of the tuple must be in the type before the dot in ``q``, and there must be no other predicate that overrides ``q`` such that this is true (see `Classes <#classes>`__ for details on overriding and root definitions). +Otherwise, the tuple must be the tuple of a fact in the store with predicate ``q``, where ``q`` shares a root definition with ``p``. The first element of the tuple must be in the type before the dot in ``q``, and there must be no other predicate that overrides ``q`` such that this is true (see `Classes <#classes>`__ for details on overriding and root definitions). An ordered tuple ``(a0, an)`` satisfies the ``+`` closure of a predicate if there is a sequence of binary tuples ``(a0, a1)``, ``(a1, a2)``, ..., ``(an-1, an)`` that all satisfy the predicate. An ordered tuple ``(a, b)`` satisfies the ``*`` closure of a predicate if it either satisfies the ``+`` closure, or if ``a`` and ``b`` are the same, and if moreover they are in each argument type of the predicate. @@ -1691,7 +1760,8 @@ The following built-in predicates are members of type ``string``: | ``trim`` | string | | The result is the receiver with all whitespace removed from the beginning and end of the string. | +----------------------+-------------+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Regular expressions are as defined by ``java.util.Pattern`` in Java. +Regular expressions are as defined by ``java.util.regex.Pattern`` in Java. +For more information, see the `Java API Documentation `__. Evaluation ---------- diff --git a/docs/language/ql-handbook/modules.rst b/docs/language/ql-handbook/modules.rst index 0d12eb606d9..6df24bf6118 100644 --- a/docs/language/ql-handbook/modules.rst +++ b/docs/language/ql-handbook/modules.rst @@ -80,9 +80,12 @@ Query modules A query module is defined by a ``.ql`` file. It can contain any of the elements listed in :ref:`module-bodies` below. -The difference is that a query module must have at least one query in its -:ref:`namespace `. This is usually a :ref:`select clause `, -but can also be a :ref:`query predicate `. +Query modules are slightly different from other modules: + +- A query module can't be imported. +- A query module must have at least one query in its + :ref:`namespace `. This is usually a :ref:`select clause `, + but can also be a :ref:`query predicate `. For example: diff --git a/docs/language/ql-handbook/name-resolution.rst b/docs/language/ql-handbook/name-resolution.rst index 3e44140640e..ef64bb0bc7e 100644 --- a/docs/language/ql-handbook/name-resolution.rst +++ b/docs/language/ql-handbook/name-resolution.rst @@ -61,31 +61,23 @@ following import statement:: import examples.security.MyLibrary -To find the precise location of this library module, the QL compiler processes the import +To find the precise location of this :ref:`library module `, the QL compiler processes the import statement as follows: #. The ``.``\ s in the qualified reference correspond to file path separators, so it first looks up ``examples/security/MyLibrary.qll`` from the directory containing ``Example.ql``. - #. If that fails, it looks up ``examples/security/MyLibrary.qll`` relative to the enclosing query - directory, if any. - This query directory is a directory containing a |queries.xml file|_, and where the contents - of that file is compatible with the current database schema. - (For example, if you are querying a JavaScript database, then the |queries.xml file|_ should - contain ````.) + #. If that fails, it looks up ``examples/security/MyLibrary.qll`` relative to the query + directory, if any. + The query directory is the first enclosing directory containing a file called ``qlpack.yml``. (Or, in legacy products, a file called ``queries.xml``.) - #. If no file is found using the above two checks, it looks up ``examples/security/MyLibrary.qll`` - relative to each library path entry. The library path depends on the environment where you - run your query, and whether you have specified any extra settings. + #. If the compiler can't find the library file using the above two checks, it looks up ``examples/security/MyLibrary.qll`` + relative to each library path entry. + The library path is usually specified using the ``libraryPathDependencies`` of the ``qlpack.yml`` file, though it may also depend on the tools you use to run your query, and whether you have specified any extra settings. + For more information, see `Library path `__ in the QL language specification. -.. |queries.xml file| replace:: ``queries.xml`` file -.. _queries.xml file: https://help.semmle.com/wiki/display/SD/queries.xml+file - If the compiler cannot resolve an import statement, then it gives a compilation error. -This process is described in more detail in the section on `module resolution `_ -in the QL language specification. - .. _selections: Selections diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 4945978eeda..b1c3d8dc09e 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -14,7 +14,8 @@ than one type. The kinds of types in QL are :ref:`primitive types `, :ref:`classes `, :ref:`character types `, :ref:`class domain types `, -:ref:`algebraic datatypes `, and :ref:`database types `. +:ref:`algebraic datatypes `, :ref:`type unions `, +and :ref:`database types `. .. index:: boolean, float, int, string, date .. _primitive-types: @@ -479,6 +480,50 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):: class Tainted extends TaintType, TTaintedValue { } +.. _type-unions: + +Type unions +*********** + +Type unions are user-defined types that are declared with the keyword ``class``. +The syntax resembles :ref:`type aliases `, but with two or more type expressions on the right-hand side. + +Type unions are used for creating restricted subsets of an existing :ref:`algebraic datatype `, by explicitly +selecting a subset of the branches of that datatype and binding them to a new type. +Type unions of :ref:`database types ` are also supported. + +You can use a type union to give a name to a subset of the branches from an algebraic datatype. +In some cases, using the type union over the whole algebraic datatype can avoid spurious +:ref:`recursion ` in predicates. +For example, the following construction is legal:: + + newtype InitialValueSource = + ExplicitInitialization(VarDecl v) { exists(v.getInitializer()) } or + ParameterPassing(Call c, int pos) { exists(c.getParameter(pos)) } or + UnknownInitialGarbage(VarDecl v) { not exists(DefiniteInitialization di | v = target(di)) } + + class DefiniteInitialization = ParameterPassing or ExplicitInitialization; + + VarDecl target(DefiniteInitialization di) { + di = ExplicitInitialization(result) or + exists(Call c, int pos | di = ParameterPassing(c, pos) and + result = c.getCallee().getFormalArg(pos)) + } + +However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid. +If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:: + + // THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion + // DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization! + class DefiniteInitialization extends InitialValueSource { + DefiniteInitialization() { + this instanceof ParameterPassing or this instanceof ExplicitInitialization + } + // ... + } + +Type unions are supported from release 2.2.0 of the CodeQL CLI. + .. _database-types: Database types diff --git a/docs/language/ql-spec/conf.py b/docs/language/ql-spec/conf.py deleted file mode 100644 index 674c5da09df..00000000000 --- a/docs/language/ql-spec/conf.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -# -# QL specifications build configuration file, created -# on Weds Nov 21 2018. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# For details of all possible config values, -# see https://www.sphinx-doc.org/en/master/usage/configuration.html - -############################################################################### -# -# Modified 22052019. - -# The configuration values below are specific to the specifications -# To amend html_theme_options, update version/release number, or add more sphinx extensions, -# refer to code/documentation/ql-documentation/global-sphinx-files/global-conf.py - -############################################################################## - -# -- Project-specific configuration ----------------------------------- - -import os - -# Import global config values -with open(os.path.abspath("../global-sphinx-files/global-conf.py")) as in_file: - exec(in_file.read()) - -# QLlexer doesn't cover everything included in the specs. -# Syntax highlighting turned off until lexer has been expanded. -highlight_language ='none' - -# The master toctree document. -master_doc = 'index' - -# Project-specific information. -project = u'QL specifications' - -# The version info for this project, if different from version and release in main conf.py file. -# The short X.Y version. -#version = u'test' -# The full version, including alpha/beta/rc tags. -#release = u'test' - -# -- Options for HTML output ---------------------------------------------- - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -html_title = 'QL specifications' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'QL specifications' - -# -- Currently unused, but potentially useful, configs-------------------------------------- - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# exclude_patterns = [] \ No newline at end of file diff --git a/docs/language/ql-spec/index.rst b/docs/language/ql-spec/index.rst deleted file mode 100644 index cba06a87746..00000000000 --- a/docs/language/ql-spec/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -README -###### - -The specifications have moved to ``ql/docs/language/ql-handbook``. -See https://github.com/github/semmle-docs/issues/21 for details of the restructuring. \ No newline at end of file diff --git a/docs/language/ql-training/cpp/intro-ql-cpp.rst b/docs/language/ql-training/cpp/intro-ql-cpp.rst index 7f398da8d4b..aa8e8cfa72b 100644 --- a/docs/language/ql-training/cpp/intro-ql-cpp.rst +++ b/docs/language/ql-training/cpp/intro-ql-cpp.rst @@ -68,7 +68,7 @@ A simple CodeQL query We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM `__, or in your `IDE `__. - A `query `__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `Introduction to query files `__. + A `query `__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `About CodeQL queries `__. In our example here, the first line of the query imports the `CodeQL library for C/C++ `__, which defines concepts like ``IfStmt`` and ``Block``. The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program. diff --git a/docs/language/ql-training/java/global-data-flow-java.rst b/docs/language/ql-training/java/global-data-flow-java.rst index 80d13fbadac..9d18083c66b 100644 --- a/docs/language/ql-training/java/global-data-flow-java.rst +++ b/docs/language/ql-training/java/global-data-flow-java.rst @@ -165,8 +165,8 @@ Add an additional taint step that (heuristically) taints a local variable if it .. code-block:: ql class TaintedOGNLConfig extends TaintTracking::Configuration { - override predicate isAdditionalTaintStep(DataFlow::Node pred, - DataFlow::Node succ) { + override predicate isAdditionalTaintStep(DataFlow::Node node1, + DataFlow::Node node2) { exists(Field f, RefType t | node1.asExpr() = f.getAnAssignedValue() and node2.asExpr() = f.getAnAccess() and diff --git a/docs/language/ql-training/java/intro-ql-java.rst b/docs/language/ql-training/java/intro-ql-java.rst index 66c41df44b0..0398ffe205d 100644 --- a/docs/language/ql-training/java/intro-ql-java.rst +++ b/docs/language/ql-training/java/intro-ql-java.rst @@ -68,7 +68,7 @@ A simple CodeQL query We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM `__, or in your `IDE `__. - A `query `__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `Introduction to query files `__. + A `query `__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `About CodeQL queries `__. In our example here, the first line of the query imports the `CodeQL library for Java `__, which defines concepts like ``IfStmt`` and ``Block``. The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ``ifStmt`` has the type ``IfStmt``, which means it represents the set of all if statements in the program. diff --git a/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql b/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql index 96d9c46a5cd..fadc74f5e6f 100644 --- a/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql +++ b/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql @@ -2,11 +2,11 @@ import cpp import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Printf -class SourceNode extends DataFlow::Node { ... } +class SourceNode extends DataFlow::Node { /* ... */ } from FormattingFunction f, Call c, SourceNode src, DataFlow::Node arg where c.getTarget() = f and arg.asExpr() = c.getArgument(f.getFormatParameterIndex()) and DataFlow::localFlow(src, arg) and not src.asExpr() instanceof StringLiteral -select arg, "Non-constant format string." \ No newline at end of file +select arg, "Non-constant format string." diff --git a/docs/language/ql-training/query-examples/java/empty-if-java-class.ql b/docs/language/ql-training/query-examples/java/empty-if-java-class.ql index 4af103396b5..e5069678158 100644 --- a/docs/language/ql-training/query-examples/java/empty-if-java-class.ql +++ b/docs/language/ql-training/query-examples/java/empty-if-java-class.ql @@ -3,10 +3,10 @@ import java class EmptyBlock extends Block { EmptyBlock() { this.getNumStmt() = 0 - + } } from IfStmt ifstmt where ifstmt.getThen() instanceof EmptyBlock -select ifstmt \ No newline at end of file +select ifstmt diff --git a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst index e2bed2b1580..b16aaa72376 100644 --- a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst +++ b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst @@ -39,9 +39,9 @@ The basic representation of an analyzed program is an *abstract syntax tree (AST The following topics contain overviews of the important AST classes and CodeQL libraries for C/C++, C#, and Java: - - `Introducing the C/C++ libraries `__ - - `Introducing the C# libraries `__ - - `Introducing the Java libraries `__ + - `CodeQL library for C/C++ `__ + - `CodeQL library for C# `__ + - `CodeQL library for Java `__ Database representations of ASTs diff --git a/docs/language/ql-training/slide-snippets/database-note.rst b/docs/language/ql-training/slide-snippets/database-note.rst index f0bfbeca07f..b35a1f1b9f4 100644 --- a/docs/language/ql-training/slide-snippets/database-note.rst +++ b/docs/language/ql-training/slide-snippets/database-note.rst @@ -4,6 +4,6 @@ You can download the database as a zip file by clicking the link on the slide ab #. Add the unzipped database to Visual Studio Code #. Upgrade the database if necessary -For further information, see `Using the extension `__ in the CodeQL for Visual Studio Code help. +For further information, see `Analyzing your projects `__ in the CodeQL for Visual Studio Code help. Note that results generated in the query console are likely to differ to those generated in CodeQL for Visual Studio Code as LGTM.com analyzes the most recent revisions of each project that has been added–the CodeQL database available to download above is based on an historical version of the codebase. \ No newline at end of file diff --git a/docs/language/ql-training/slide-snippets/intro-ql-general.rst b/docs/language/ql-training/slide-snippets/intro-ql-general.rst index 8c0d02d6a6f..f07f5907c15 100644 --- a/docs/language/ql-training/slide-snippets/intro-ql-general.rst +++ b/docs/language/ql-training/slide-snippets/intro-ql-general.rst @@ -42,7 +42,7 @@ Zoom in on the code... The pseudocode in the slide illustrates this. The function is declared to take an array of length 12 (presumably three data points for each thruster). - However, there’s no sanity checking, and a developer might call it with an array that’s too short, holding direction information for only one of the thrusters. + However, there’s no bounds checking, and a developer might call it with an array that’s too short, holding direction information for only one of the thrusters. The function will then read past the end of the array, and unpredictable results occur. Write a query... diff --git a/docs/language/ql-training/slide-snippets/local-data-flow.rst b/docs/language/ql-training/slide-snippets/local-data-flow.rst index 0bbb2c20ba4..c660d83d21a 100644 --- a/docs/language/ql-training/slide-snippets/local-data-flow.rst +++ b/docs/language/ql-training/slide-snippets/local-data-flow.rst @@ -70,7 +70,7 @@ Local vs global data flow For further information, see: - - `Introduction to data flow analysis with CodeQL `__ + - `About data flow analysis `__ .. rst-class:: background2 diff --git a/docs/language/reusables/abstract-syntax-tree.rst b/docs/language/reusables/abstract-syntax-tree.rst new file mode 100644 index 00000000000..a62c9f73dd2 --- /dev/null +++ b/docs/language/reusables/abstract-syntax-tree.rst @@ -0,0 +1 @@ +The `abstract syntax tree (AST) `__ represents the syntactic structure of a program. Nodes on the AST represent elements such as statements and expressions. \ No newline at end of file diff --git a/docs/language/reusables/codeql-ref-tools-further-reading.rst b/docs/language/reusables/codeql-ref-tools-further-reading.rst new file mode 100644 index 00000000000..55f7ad4dddd --- /dev/null +++ b/docs/language/reusables/codeql-ref-tools-further-reading.rst @@ -0,0 +1,2 @@ +- `QL language reference `__ +- `CodeQL tools `__ \ No newline at end of file diff --git a/docs/language/reusables/cpp-further-reading.rst b/docs/language/reusables/cpp-further-reading.rst new file mode 100644 index 00000000000..9c68386c0fa --- /dev/null +++ b/docs/language/reusables/cpp-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for C and C++ `__ +- `Example queries for C and C++ `__ +- `CodeQL library reference for C and C++ `__ + diff --git a/docs/language/reusables/csharp-further-reading.rst b/docs/language/reusables/csharp-further-reading.rst new file mode 100644 index 00000000000..eff3327b69d --- /dev/null +++ b/docs/language/reusables/csharp-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for C# `__ +- `Example queries for C# `__ +- `CodeQL library reference for C# `__ + diff --git a/docs/language/reusables/go-further-reading.rst b/docs/language/reusables/go-further-reading.rst new file mode 100644 index 00000000000..a624bcfd7ce --- /dev/null +++ b/docs/language/reusables/go-further-reading.rst @@ -0,0 +1,3 @@ +- `CodeQL queries for Go `__ +- `Example queries for Go `__ +- `CodeQL library reference for Go `__ diff --git a/docs/language/reusables/java-further-reading.rst b/docs/language/reusables/java-further-reading.rst new file mode 100644 index 00000000000..16afdcbf790 --- /dev/null +++ b/docs/language/reusables/java-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for Java `__ +- `Example queries for Java `__ +- `CodeQL library reference for Java `__ + diff --git a/docs/language/reusables/javascript-further-reading.rst b/docs/language/reusables/javascript-further-reading.rst new file mode 100644 index 00000000000..12321f6a539 --- /dev/null +++ b/docs/language/reusables/javascript-further-reading.rst @@ -0,0 +1,3 @@ +- `CodeQL queries for JavaScript `__ +- `Example queries for JavaScript `__ +- `CodeQL library reference for JavaScript `__ diff --git a/docs/language/reusables/python-further-reading.rst b/docs/language/reusables/python-further-reading.rst new file mode 100644 index 00000000000..8a6eb162066 --- /dev/null +++ b/docs/language/reusables/python-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for Python `__ +- `Example queries for Python `__ +- `CodeQL library reference for Python `__ + diff --git a/docs/language/reusables/python-other-resources.rst b/docs/language/reusables/python-other-resources.rst deleted file mode 100644 index 8e9482cf230..00000000000 --- a/docs/language/reusables/python-other-resources.rst +++ /dev/null @@ -1,3 +0,0 @@ -- "`QL language reference `__" -- `Python cookbook queries `__ in the Semmle wiki -- `Python queries in action `__ on LGTM.com diff --git a/docs/language/support/language-support.rst b/docs/language/support/language-support.rst index 4aebb9957d6..b716b802427 100644 --- a/docs/language/support/language-support.rst +++ b/docs/language/support/language-support.rst @@ -6,8 +6,6 @@ CodeQL and LGTM version |version| support analysis of the following languages co Note that where there are several versions or dialects of a language, the supported variants are listed. If your code requires a particular version of a compiler, check that this version is included below. -Customers with any questions should contact their usual Semmle contact with any questions. -If you're not a customer yet, contact us at info@semmle.com -with any questions you have about language and compiler support. +If you have any questions about language and compiler support, you can find help on the `GitHub Security Lab discussions board `__. .. include:: reusables/versions-compilers.rst diff --git a/docs/language/support/reusables/frameworks.rst b/docs/language/support/reusables/frameworks.rst index 1b8e85e60e2..d148f5d124e 100644 --- a/docs/language/support/reusables/frameworks.rst +++ b/docs/language/support/reusables/frameworks.rst @@ -71,6 +71,7 @@ JavaScript and TypeScript built-in support sqlite3, Database superagent, Network communicator underscore, Utility library + vue, HTML framework diff --git a/docs/language/support/reusables/versions-compilers.rst b/docs/language/support/reusables/versions-compilers.rst index 3b244e592bd..329cf95648b 100644 --- a/docs/language/support/reusables/versions-compilers.rst +++ b/docs/language/support/reusables/versions-compilers.rst @@ -11,23 +11,22 @@ Microsoft extensions (up to VS 2019), 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, + C#,C# up to 8.0,"Microsoft Visual Studio up to 2019 with .NET up to 4.8, - .NET Core up to 3.0","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" + .NET Core up to 3.1","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" Go (aka Golang), "Go up to 1.14", "Go 1.11 or more recent", ``.go`` - Java,"Java 6 to 14 [4]_","javac (OpenJDK and Oracle JDK), + Java,"Java 6 to 14 [3]_","javac (OpenJDK and Oracle JDK), - Eclipse compiler for Java (ECJ) [5]_",``.java`` - JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_" + Eclipse compiler for Java (ECJ) [4]_",``.java`` + JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [5]_" Python,"2.7, 3.5, 3.6, 3.7, 3.8",Not applicable,``.py`` - TypeScript [7]_,"2.6-3.7",Standard TypeScript compiler,"``.ts``, ``.tsx``" + TypeScript [6]_,"2.6-3.7",Standard TypeScript compiler,"``.ts``, ``.tsx``" .. container:: footnote-group .. [1] Support for the clang-cl compiler is preliminary. .. [2] Support for the Arm Compiler (armcc) is preliminary. - .. [3] In addition, support is included for the preview features of C# 8.0 and .NET Core 3.0. - .. [4] Builds that execute on Java 6 to 14 can be analyzed. The analysis understands Java 14 standard language features. - .. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. - .. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. - .. [7] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default for LGTM. + .. [3] Builds that execute on Java 6 to 14 can be analyzed. The analysis understands Java 14 standard language features. + .. [4] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. + .. [5] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. + .. [6] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default for LGTM. diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md new file mode 100644 index 00000000000..519b0622818 --- /dev/null +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -0,0 +1,474 @@ +# Using the shared data-flow library + +This document is aimed towards language maintainers and contains implementation +details that should be mostly irrelevant to query writers. + +## Overview + +The shared data-flow library implements sophisticated global data flow on top +of a language-specific data-flow graph. The language-specific bits supply the +graph through a number of predicates and classes, and the shared implementation +takes care of matching call-sites with returns and field writes with reads to +ensure that the generated paths are well-formed. The library also supports a +number of additional features for improving precision, for example pruning +infeasible paths based on type information. + +## File organisation + +The data-flow library consists of a number of files typically located in +`/dataflow` and `/dataflow/internal`: + +``` +dataflow/DataFlow.qll +dataflow/internal/DataFlowImpl.qll +dataflow/internal/DataFlowCommon.qll +dataflow/internal/DataFlowImplSpecific.qll +``` + +`DataFlow.qll` provides the user interface for the library and consists of just +a few lines of code importing the implementation: + +#### `DataFlow.qll` +```ql +import + +module DataFlow { + import semmle.code.java.dataflow.internal.DataFlowImpl +} +``` + +The `DataFlowImpl.qll` and `DataFlowCommon.qll` files contain the library code +that is shared across languages. These contain `Configuration`-specific and +`Configuration`-independent code, respectively. This organization allows +multiple copies of the library to exist without duplicating the +`Configuration`-independent predicates (for the use case when a query wants to +use two instances of global data flow and the configuration of one depends on +the results from the other). Using multiple copies just means duplicating +`DataFlow.qll` and `DataFlowImpl.qll`, for example as: + +``` +dataflow/DataFlow2.qll +dataflow/DataFlow3.qll +dataflow/internal/DataFlowImpl2.qll +dataflow/internal/DataFlowImpl3.qll +``` + +The file `DataFlowImplSpecific.qll` provides all the language-specific classes +and predicates that the library needs as input and is the topic of the rest of +this document. + +This file must provide two modules named `Public` and `Private`, which the +shared library code will import publicly and privately, respectively, thus +allowing the language-specific part to choose which classes and predicates +should be exposed by `DataFlow.qll`. + +A typical implementation looks as follows, thereby organizing the predicates in +two files, which we'll subsequently assume: + +#### `DataFlowImplSpecific.qll` +```ql +module Private { + import DataFlowPrivate +} + +module Public { + import DataFlowPublic +} +``` + +## Defining the data-flow graph + +The main input to the library is the data-flow graph. One must define a class +`Node` and an edge relation `simpleLocalFlowStep(Node node1, Node node2)`. The +`Node` class should be in `DataFlowPublic`. + +Recommendations: +* Make `Node` an IPA type. There is commonly a need for defining various + data-flow nodes that are not necessarily represented in the AST of the + language. +* Define `predicate localFlowStep(Node node1, Node node2)` as an alias of + `simpleLocalFlowStep` and expose it publicly. The reason for this indirection + is that it gives the option of exposing local flow augmented with field flow. + See the C/C++ implementation, which makes use of this feature. Another use of + this indirection is to hide synthesized local steps that are only relevant + for global flow. See the C# implementation for an example of this. +* Define `predicate localFlow(Node node1, Node node2) { localFlowStep*(node1, node2) }`. +* Make the local flow step relation in `simpleLocalFlowStep` follow + def-to-first-use and use-to-next-use steps for SSA variables. Def-use steps + also work, but the upside of `use-use` steps is that sources defined in terms + of variable reads just work out of the box. It also makes certain + barrier-implementations simpler. + +The shared library does not use `localFlowStep` nor `localFlow` but users of +`DataFlow.qll` may expect the existence of `DataFlow::localFlowStep` and +`DataFlow::localFlow`. + +### `Node` subclasses + +The `Node` class needs a number of subclasses. As a minimum the following are needed: +``` +ExprNode +ParameterNode +PostUpdateNode + +OutNode +ArgumentNode +ReturnNode +CastNode +``` +and possibly more depending on the language and its AST. Of the above, the +first 3 should be public, but the last 4 can be private. Also, the last 4 will +likely be subtypes of `ExprNode`. For further details about `ParameterNode`, +`ArgumentNode`, `ReturnNode`, and `OutNode` see [The call-graph](#the-call-graph) +below. For further details about `CastNode` see [Type pruning](#type-pruning) below. +For further details about `PostUpdateNode` see [Field flow](#field-flow) below. + +Nodes corresponding to expressions and parameters are the most common for users +to interact with so a couple of convenience predicates are generally included: +``` +DataFlowExpr Node::asExpr() +Parameter Node::asParameter() +ExprNode exprNode(DataFlowExpr n) +ParameterNode parameterNode(Parameter n) +``` +Here `DataFlowExpr` should be an alias for the language-specific class of +expressions (typically called `Expr`). Parameters do not need an alias for the +shared implementation to refer to, so here you can just use the +language-specific class name (typically called `Parameter`). + +### The call-graph + +In order to make inter-procedural flow work a number of classes and predicates +must be provided. + +First, two types, `DataFlowCall` and `DataFlowCallable`, must be defined. These +should be aliases for whatever language-specific class represents calls and +callables (a "callable" is intended as a broad term covering functions, +methods, constructors, lambdas, etc.). It can also be useful to represent +`DataFlowCall` as an IPA type if implicit calls need to be modelled. The +call-graph should be defined as a predicate: +```ql +DataFlowCallable viableCallable(DataFlowCall c) +``` + +In order to connect data-flow across calls, the 4 `Node` subclasses +`ArgumentNode`, `ParameterNode`, `ReturnNode`, and `OutNode` are used. +Flow into callables from arguments to parameters are matched up using an +integer position, so these two classes must define: +```ql +ArgumentNode::argumentOf(DataFlowCall call, int pos) +ParameterNode::isParameterOf(DataFlowCallable c, int pos) +``` +It is typical to use `pos = -1` for an implicit `this`-parameter. + +For most languages return-flow is simpler and merely consists of matching up a +`ReturnNode` with the data-flow node corresponding to the value of the call, +represented as `OutNode`. For this use-case we would define a singleton type +`ReturnKind`, a trivial `ReturnNode::getKind()`, and `getAnOutNode` to relate +calls and `OutNode`s: +```ql +private newtype TReturnKind = TNormalReturnKind() + +ReturnKind ReturnNode::getKind() { any() } + +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { + result = call.getNode() and + kind = TNormalReturnKind() +} +``` + +For more complex use-cases when a language allows a callable to return multiple +values, for example through `out` parameters in C#, the `ReturnKind` class can +be defined and used to match up different kinds of `ReturnNode`s with the +corresponding `OutNode`s. + +## Flow through global variables + +Flow through global variables are called jump-steps, since such flow steps +essentially jump from one callable to another completely discarding call +contexts. + +Adding support for this type of flow is done with the following predicate: +```ql +predicate jumpStep(Node node1, Node node2) +``` + +If global variables are common and certain databases have many reads and writes +of the same global variable, then a direct step may have performance problems, +since the straight-forward implementation is just a cartesian product of reads +and writes for each global variable. In this case it can be beneficial to +remove the cartesian product by introducing an intermediate `Node` for the +value of each global variable. + +Note that, jump steps of course also can be used to implement other +cross-callable flow. As an example Java also uses this mechanism for variable +capture flow. But beware that this will lose the call context, so normal +inter-procedural flow should use argument-parameter-, and return-outnode-flow +as described above. + +## Field flow + +The library supports tracking flow through field stores and reads. In order to +support this, a class `Content` and two predicates +`storeStep(Node node1, Content f, Node node2)` and +`readStep(Node node1, Content f, Node node2)` must be defined. It generally +makes sense for stores to target `PostUpdateNode`s, but this is not a strict +requirement. Besides this, certain nodes must have associated +`PostUpdateNode`s. The node associated with a `PostUpdateNode` should be +defined by `PostUpdateNode::getPreUpdateNode()`. + +`PostUpdateNode`s are generally used when we need two data-flow nodes for a +single AST element in order to distinguish the value before and after some +side-effect (typically a field store, but it may also be addition of taint +through an additional step targeting a `PostUpdateNode`). + +It is recommended to introduce `PostUpdateNode`s for all `ArgumentNode`s (this +can be skipped for immutable arguments), and all field qualifiers for both +reads and stores. + +Remember to define local flow for `PostUpdateNode`s as well in +`simpleLocalFlowStep`. In general out-going local flow from `PostUpdateNode`s +should be use-use flow, and there is generally no need for in-going local flow +edges for `PostUpdateNode`s. + +We will illustrate how the shared library makes use of `PostUpdateNode`s +through a couple of examples. + +### Example 1 + +Consider the following setter and its call: +``` +setFoo(obj, x) { + sink1(obj.foo); + obj.foo = x; +} + +setFoo(myobj, source); +sink2(myobj.foo); +``` +Here `source` should flow to the argument of `sink2` but not the argument of +`sink1`. The shared library handles most of the complexity involved in this +flow path, but needs a little bit of help in terms of available nodes. In +particular it is important to be able to distinguish between the value of the +`myobj` argument to `setFoo` before the call and after the call, since without +this distinction it is hard to avoid also getting flow to `sink1`. The value +before the call should be the regular `ArgumentNode` (which will get flow into +the call), and the value after the call should be a `PostUpdateNode`. Thus a +`PostUpdateNode` should exist for the `myobj` argument with the `ArgumentNode` +as its pre-update node. In general `PostUpdateNode`s should exist for any +mutable `ArgumentNode`s to support flow returning through a side-effect +updating the argument. + +This example also suggests how `simpleLocalFlowStep` should be implemented for +`PostUpdateNode`s: we need a local flow step between the `PostUpdateNode` for +the `myobj` argument and the following `myobj` in the qualifier of `myobj.foo`. + +Inside `setFoo` the actual store should also target a +`PostUpdateNode` - in this case associated with the qualifier `obj` - as this +is the mechanism the shared library uses to identify side-effects that should +be reflected at call sites as setter-flow. The shared library uses the +following rule to identify setters: If the value of a parameter may flow to a +node that is the pre-update node of a `PostUpdateNode` that is reached by some +flow, then this represents an update to the parameter, which will be reflected +in flow continuing to the `PostUpdateNode` of the corresponding argument in +call sites. + +### Example 2 + +In the following two lines we would like flow from `x` to reach the +`PostUpdateNode` of `a` through a sequence of two store steps, and this is +indeed handled automatically by the shared library. +``` +a.b.c = x; +a.getB().c = x; +``` +The only requirement for this to work is the existence of `PostUpdateNode`s. +For a specified read step (in `readStep(Node n1, Content f, Node n2)`) the +shared library will generate a store step in the reverse direction between the +corresponding `PostUpdateNode`s. A similar store-through-reverse-read will be +generated for calls that can be summarized by the shared library as getters. +This usage of `PostUpdateNode`s ensures that `x` will not flow into the `getB` +call after reaching `a`. + +### Example 3 + +Consider a constructor and its call (for this example we will use Java, but the +idea should generalize): +```java +MyObj(Content content) { + this.content = content; +} + +obj = new MyObj(source); +sink(obj.content); +``` + +We would like the constructor call to act in the same way as a setter, and +indeed this is quite simple to achieve. We can introduce a synthetic data-flow +node associated with the constructor call, let us call it `MallocNode`, and +make this an `ArgumentNode` with position `-1` such that it hooks up with the +implicit `this`-parameter of the constructor body. Then we can set the +corresponding `PostUpdateNode` of the `MallocNode` to be the constructor call +itself as this represents the value of the object after construction, that is +after the constructor has run. With this setup of `ArgumentNode`s and +`PostUpdateNode`s we will achieve the desired flow from `source` to `sink` + +### Field flow barriers + +Consider this field flow example: +``` +obj.f = source; +obj.f = safeValue; +sink(obj.f); +``` +or the similar case when field flow is used to model collection content: +``` +obj.add(source); +obj.clear(); +sink(obj.get(key)); +``` +Clearing a field or content like this should act as a barrier, and this can be +achieved by marking the relevant `Node, Content` pair as a clear operation in +the `clearsContent` predicate. A reasonable default implementation for fields +looks like this: +```ql +predicate clearsContent(Node n, Content c) { + n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() +} +``` +However, this relies on the local step relation using the smallest possible +use-use steps. If local flow is implemented using def-use steps, then +`clearsContent` might not be easy to use. + +## Type pruning + +The library supports pruning paths when a sequence of value-preserving steps +originate in a node with one type, but reaches a node with another and +incompatible type, thus making the path impossible. + +The type system for this is specified with the class `DataFlowType` and the +compatibility relation `compatibleTypes(DataFlowType t1, DataFlowType t2)`. +Using a singleton type as `DataFlowType` means that this feature is effectively +disabled. + +It can be useful to use a simpler type system for pruning than whatever type +system might come with the language, as collections of types that would +otherwise be equivalent with respect to compatibility can then be represented +as a single entity (this improves performance). As an example, Java uses erased +types for this purpose and a single equivalence class for all numeric types. + +The type of a `Node` is given by the following predicate +``` +DataFlowType getNodeType(Node n) +``` +and every `Node` should have a type. + +One also needs to define the string representation of a `DataFlowType`: +``` +string ppReprType(DataFlowType t) +``` +The `ppReprType` predicate is used for printing a type in the labels of +`PathNode`s, this can be defined as `none()` if type pruning is not used. + +Finally, one must define `CastNode` as a subclass of `Node` as those nodes +where types should be checked. Usually this will be things like explicit casts. +The shared library will also check types at `ParameterNode`s and `OutNode`s +without needing to include these in `CastNode`. It is semantically perfectly +valid to include all nodes in `CastNode`, but this can hurt performance as it +will reduce the opportunity for the library to compact several local steps into +one. It is also perfectly valid to leave `CastNode` as the empty set, and this +should be the default if type pruning is not used. + +## Virtual dispatch with call context + +Consider a virtual call that may dispatch to multiple different targets. If we +know the call context of the call then this can sometimes be used to reduce the +set of possible dispatch targets and thus eliminate impossible call chains. + +The library supports a one-level call context for improving virtual dispatch. + +Conceptually, the following predicate should be implemented as follows: +```ql +DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + exists(DataFlowCallable enclosing | + result = viableCallable(call) and + enclosing = call.getEnclosingCallable() and + enclosing = viableCallable(ctx) + | + not ... <`result` is impossible target for `call` given `ctx`> ... + ) +} +``` +However, joining the virtual dispatch relation with itself in this way is +usually way too big to be feasible. Instead, the relation above should only be +defined for those values of `call` for which the set of resulting dispatch +targets might be reduced. To do this, define the set of `call`s that might for +some reason benefit from a call context as the following predicate (the `c` +column should be `call.getEnclosingCallable()`): +```ql +predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) +``` +And then define `DataFlowCallable viableImplInCallContext(DataFlowCall call, +DataFlowCall ctx)` as sketched above, but restricted to +`mayBenefitFromCallContext(call, _)`. + +The shared implementation will then compare counts of virtual dispatch targets +using `viableCallable` and `viableImplInCallContext` for each `call` in +`mayBenefitFromCallContext(call, _)` and track call contexts during flow +calculation when differences in these counts show an improved precision in +further calls. + +## Additional features + +### Access path length limit + +The maximum length of an access path is the maximum number of nested stores +that can be tracked. This is given by the following predicate: +```ql +int accessPathLimit() { result = 5 } +``` +We have traditionally used 5 as a default value here, and real examples have +been observed to require at least this much. Changing this value has a direct +impact on performance for large databases. + +### Hidden nodes + +Certain synthetic nodes can be hidden to exclude them from occurring in path +explanations. This is done through the following predicate: +```ql +predicate nodeIsHidden(Node n) +``` + +### Unreachable nodes + +Consider: +``` +foo(source1, false); +foo(source2, true); + +foo(x, b) { + if (b) + sink(x); +} +``` +Sometimes certain data-flow nodes can be unreachable based on the call context. +In the above example, only `source2` should be able to reach `sink`. This is +supported by the following predicate where one can specify unreachable nodes +given a call context. +```ql +predicate isUnreachableInCall(Node n, DataFlowCall callcontext) { .. } +``` +Note that while this is a simple interface it does have some scalability issues +if the number of unreachable nodes is large combined with many call sites. + +### `BarrierGuard`s + +The class `BarrierGuard` must be defined. See +https://github.com/github/codeql/pull/1718 for details. + +### Consistency checks + +The file `dataflow/internal/DataFlowImplConsistency.qll` contains a number of +consistency checks to verify that the language-specfic parts satisfy the +invariants that are expected by the shared implementation. Run these queries to +check for inconsistencies. diff --git a/docs/ql-style-guide.md b/docs/ql-style-guide.md index 495f7bf6ea9..fba407ae8dd 100644 --- a/docs/ql-style-guide.md +++ b/docs/ql-style-guide.md @@ -214,79 +214,7 @@ class Type extends ... { ## Documentation -General requirements: - -1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/QLDocSpecification.html). -1. Use `/** ... */` for documentation, even for single line comments. -1. For single-line documentation, the `/**` and `*/` are written on the same line as the comment. -1. For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. -1. Use full sentences, with capital letters and full stops. -1. Use American English. -1. Documentation comments *should* be appropriate for users of the code. -1. Documentation for maintainers of the code *must* use normal comments. - -Documentation for specific items: - -1. Public declarations *must* be documented. -1. Non-public declarations *should* be documented. -1. Declarations in query files *should* be documented. -1. Library files (`.qll` files) *should* be have a documentation comment at the top of the file. -1. Query files, except for tests, *must* have a QLDoc query documentation comment at the top of the file. -1. Predicates that do not have a result *should* be documented `/** Holds if ... */` -1. Predicates that have a result *should* be documented `/** Gets ... */` -1. All predicate parameters *should* be referred to in the predicate documentation. -1. Reference names, such as types and parameters, using backticks `` ` ``. -1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. -1. Classes *should* be documented in the singular, for example `/* An expression. */` -1. Where a class denotes a generic concept with subclasses, list those subclasses. -1. Declarations that are deprecated *should* be documented as `DEPRECATED: ...` -1. Declarations that are for internal use *should* be documented as `INTERNAL: Do not use`. - -### Examples - -```ql -/** Provides logic for determining constant expressions. */ -``` - -```ql -/** - * Holds if the qualifier of this call has type `qualifierType`. - * `isExactType` indicates whether the type is exact, that is, whether - * the qualifier is guaranteed not to be a subtype of `qualifierType`. - */ -``` -```ql -/** - * A delegate declaration, for example - * ``` - * delegate void Logger(string text); - * ``` - */ -class Delegate extends ... -``` - -```ql -/** - * An element that can be called. - * - * Either a method (`Method`), a constructor (`Constructor`), a destructor - * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), - * an anonymous function (`AnonymousFunctionExpr`), or a local function - * (`LocalFunction`). - */ -class Callable extends ... -``` - -```ql -/** DEPRECATED: Use `getAnExpr()` instead. */ -deprecated Expr getInitializer() -``` - -```ql -/** - * INTERNAL: Do not use. - */ -``` +For more information about documenting the code that you contribute to this repository, see the [QLDoc style guide](qldoc-style-guide.md). ## Formulas 1. *Prefer* one *conjunct* per line. @@ -417,16 +345,16 @@ deprecated Expr getInitializer() | Phrase | Meaning | |-------------|----------| -| *[annotation](https://help.semmle.com/QL/QLLanguageSpecification.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. | +| *[annotation](https://help.semmle.com/QL/ql-handbook/language.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. | | *body* | The text inside `{ }`, `( )`, or each section of an `if`-`then`-`else` or `from`-`where`-`select`. | | *binary operator* | An operator with two operands, such as comparison operators, `and`, `or`, `implies`, or arithmetic operators. | | *call* | A *formula* that invokes a predicate, e.g. `this.isStatic()` or `calls(a,b)`. | -| *[conjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#conjunctions)* | A formula that is an operand to an `and`. | +| *[conjunct](https://help.semmle.com/QL/ql-handbook/language.html#conjunctions)* | A formula that is an operand to an `and`. | | *declaration* | A class, module, predicate, field or newtype. | -| *[disjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#disjunctions)* | A formula that is an operand to an `or`. | -| *[formula](https://help.semmle.com/QL/QLLanguageSpecification.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. | +| *[disjunct](https://help.semmle.com/QL/ql-handbook/language.html#disjunctions)* | A formula that is an operand to an `or`. | +| *[formula](https://help.semmle.com/QL/ql-handbook/language.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. | | *should/should not/avoid/prefer* | Adhere to this rule wherever possible, where it makes sense. | | *may/can* | This is a reasonable alternative, to be used with discretion. | | *must/always/do not* | Always adhere to this rule. | -| *[quantifier/aggregation](https://help.semmle.com/QL/QLLanguageSpecification.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. | +| *[quantifier/aggregation](https://help.semmle.com/QL/ql-handbook/language.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. | | *variable* | A parameter to a predicate, a field, a from variable, or a variable introduced by a *quantifier* or *aggregation*. | diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md new file mode 100644 index 00000000000..79871ae8d9f --- /dev/null +++ b/docs/qldoc-style-guide.md @@ -0,0 +1,184 @@ +# QLDoc style guide + +## Introduction + +Valid QL comments are known as QLDoc. This document describes the recommended styles and conventions you should use when writing QLDoc for code contributions in this repository. If there is a conflict between any of the recommendations in this guide and clarity, then clarity should take precedence. + +### General requirements + +1. Documentation must adhere to the [QLDoc specification](https://help.semmle.com/QL/ql-handbook/qldoc.html). +1. Documentation comments should be appropriate for users of the code. +1. Documentation for maintainers of the code must use normal comments. +1. Use `/** ... */` for documentation, even for single line comments. + - For single-line documentation, the `/**` and `*/` are written on the same line as the comment. + - For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. +1. Use code formatting (backticks) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). +1. Give explanatory examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. + + +### Language requirements + +1. Use American English. +1. Use full sentences, with capital letters and periods, except for the initial sentence of the comment, which may be fragmentary as described below. +1. Use simple sentence structures and avoid complex or academic language. +1. Avoid colloquialisms and contractions. +1. Use words that are in common usage. + + +### Requirements for specific items + +1. Public declarations must be documented. +1. Non-public declarations should be documented. +1. Declarations in query files should be documented. +1. Library files (`.qll` files) should be have a documentation comment at the top of the file. +1. Query files, except for tests, must have a QLDoc query documentation comment at the top of the file. + +## QLDoc for predicates + +1. Refer to all predicate parameters in the predicate documentation. +1. Reference names, such as types and parameters, using backticks `` ` ``. +1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. +1. Predicates that override a single predicate don't need QLDoc, as they will inherit it. + +### Predicates without result + +1. Use a third-person verb phrase of the form ``Holds if `arg` has .`` +1. Avoid: + - `/** Whether ... */` + - `/**" Relates ... */` + - Question forms: + - ``/** Is `x` a foo? */`` + - ``/** Does `x` have a bar? */`` + +#### Example + +```ql +/** + * Holds if the qualifier of this call has type `qualifierType`. + * `isExactType` indicates whether the type is exact, that is, whether + * the qualifier is guaranteed not to be a subtype of `qualifierType`. + */ +``` + +### Predicates with result + +1. Use a third-person verb phrase of the form `Gets (a|the) .` +1. Use "if any" if the item is usually unique but might be missing. For example +`Gets the body of this method, if any.` +1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example +``Holds if `result` is a child of this expression.`` +1. Avoid: + - `Get a ...` + - `The ...` + - `Results in ...` + - Any use of `return` + +#### Example +```ql +/** + * Gets the expression denoting the super class of this class, + * or nothing if this is an interface or a class without an `extends` clause. + */ +``` + +### Deprecated predicates + +The documentation for deprecated predicates should be updated to emphasize the deprecation and specify what predicate to use as an alternative. +Insert a sentence of the form `DEPRECATED: Use instead.` at the start of the QLDoc comment. + +#### Example + +```ql +/** DEPRECATED: Use `getAnExpr()` instead. */ +deprecated Expr getInitializer() +``` + +### Internal predicates + +Some predicates are internal-only declarations that cannot be made private. The documentation for internal predicates should begin with `INTERNAL: Do not use.` + +#### Example + +```ql +/** + * INTERNAL: Do not use. + */ +``` + +### Special predicates + +Certain special predicates should be documented consistently. + +- Always document `toString` as + + ```ql + /** Gets a textual representation of this element. */ + string toString() { ... } + ``` + +- Always document `hasLocationInfo` as + + ```ql + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/locations.html). + */ + + predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { ... } + ``` +## QLDoc for classes + +1. Document classes using a noun phrase of the form `A that .` +1. Use "that", not "which". +1. Refer to member elements in the singular. +1. Where a class denotes a generic concept with subclasses, list those subclasses. + +#### Example + +```ql +/** + * A delegate declaration, for example + * ``` + * delegate void Logger(string text); + * ``` + */ +class Delegate extends ... +``` + +```ql +/** + * An element that can be called. + * + * Either a method (`Method`), a constructor (`Constructor`), a destructor + * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), + * an anonymous function (`AnonymousFunctionExpr`), or a local function + * (`LocalFunction`). + */ +class Callable extends ... +``` + +## QLDoc for modules + +Modules should be documented using a third-person verb phrase of the form `Provides .` + +#### Example + +```ql +/** Provides logic for determining constant expressions. */ +``` +```ql +/** Provides classes representing the control flow graph within functions. */ +``` + +## Special variables + +When referring to `this`, you may either refer to it as `` `this` `` or `this `. For example: +- ``Holds if `this` is static.`` +- `Holds if this method is static.` + +When referring to `result`, you may either refer to it as `` `result` `` or as `the result`. For example: +- ``Holds if `result` is a child of this expression.`` +- `Holds if the result is a child of this expression.` diff --git a/docs/query-help-style-guide.md b/docs/query-help-style-guide.md index 147e18d5aac..f8584cb5e98 100644 --- a/docs/query-help-style-guide.md +++ b/docs/query-help-style-guide.md @@ -36,7 +36,7 @@ Section-level elements are used to group the information within the query help f 3. `example`—an example of code showing the problem. Where possible, this section should also include a solution to the issue. 4. `references`—relevant references, such as authoritative sources on language semantics and best practice. -For further information about the other section-level, block, list and table elements supported by query help files, see the [Query help reference](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-help.html) on help.semmle.com. +For further information about the other section-level, block, list and table elements supported by query help files, see [Query help files](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-help.html) on help.semmle.com. ## English style diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 20d09ad29db..1311a808e3a 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -11,8 +11,7 @@ Query files have the extension `.ql`. Each file has two distinct areas: * Metadata area–displayed at the top of the file, contains the metadata that defines how results for the query are interpreted and gives a brief description of the purpose of the query. * Query definition–defined using QL. The query includes a select statement, which defines the content and format of the results. For further information about writing QL, see the following topics: * [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html) - * [QL language handbook](https://help.semmle.com/QL/ql-handbook/index.html) - * [QL language specification](https://help.semmle.com/QL/ql-spec/language.html) + * [QL language reference](https://help.semmle.com/QL/ql-handbook/index.html) * [CodeQL style guide](https://github.com/github/codeql/blob/master/docs/ql-style-guide.md) @@ -20,13 +19,14 @@ For examples of query files for the languages supported by CodeQL, visit the fol * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) ## Metadata area -Query file metadata contains important information that defines the identifier and purpose of the query. The metadata is included as the content of a valid [QLDoc](https://help.semmle.com/QL/ql-spec/qldoc.html) comment, on lines with leading whitespace followed by `*`, between an initial `/**` and a trailing `*/`. For example: +Query file metadata contains important information that defines the identifier and purpose of the query. The metadata is included as the content of a valid [QLDoc](https://help.semmle.com/QL/ql-handbook/qldoc.html) comment, on lines with leading whitespace followed by `*`, between an initial `/**` and a trailing `*/`. For example: ``` /** @@ -42,7 +42,7 @@ Query file metadata contains important information that defines the identifier a */ ``` -To help others use your query, and to ensure that the query works correctly on LGTM, you should include all of the required information outlined below in the metadata, and as much of the optional information as possible. For further information on query metadata see [Query metadata](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-metadata.html) on help.semmle.com. +To help others use your query, and to ensure that the query works correctly on LGTM, you should include all of the required information outlined below in the metadata, and as much of the optional information as possible. For further information on query metadata see [Metadata for CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-metadata.html) on help.semmle.com. @@ -134,6 +134,7 @@ There are also more specific `@tags` that can be added. See, the following pages * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) @@ -158,7 +159,7 @@ When you tag a query like this, the associated CWE pages from [MITRE.org](http:/ ## QL area -### Alert messages +### Alert messages The select clause of each alert query defines the alert message that is displayed for each result found by the query. Alert messages are strings that concisely describe the problem that the alert is highlighting and, if possible, also provide some context. For consistency, alert messages should adhere to the following guidelines: @@ -167,14 +168,15 @@ The select clause of each alert query defines the alert message that is displaye * Program element references should be in 'single quotes' to distinguish them from ordinary words. Quotes are not needed around substitutions ($@). * Avoid constant alert message strings and include some context, if possible. For example, `The class 'Foo' is duplicated as 'Bar'.` is preferable to `This class is duplicated here.` * Where you reference another program element, link to it if possible using a substitution (`$@`). Links should be used inline in the sentence, rather than as parenthesised lists or appositions. -* When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining select statements](https://help.semmle.com/QL/learn-ql/ql/writing-queries/select-statement.html). +* When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining the results of a query](https://help.semmle.com/QL/learn-ql/ql/writing-queries/select-statement.html). For examples of select clauses and alert messages, see the query source files at the following pages: * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) -For further information on query writing, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html). For more information on learning CodeQL, see [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html). +For further information on query writing, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html). For more information on learning CodeQL, see [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html). diff --git a/java/ql/src/Advisory/Documentation/JavadocCommon.qll b/java/ql/src/Advisory/Documentation/JavadocCommon.qll index 2de736e2697..5c38e4e55ec 100644 --- a/java/ql/src/Advisory/Documentation/JavadocCommon.qll +++ b/java/ql/src/Advisory/Documentation/JavadocCommon.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates related to Javadoc conventions. */ + import java /** Holds if the given `Javadoc` contains a minimum of a few characters of text. */ @@ -29,6 +31,7 @@ class DocuRefType extends RefType { this.isPublic() } + /** Holds if the Javadoc for this type contains a minimum of a few characters of text. */ predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) } } @@ -46,8 +49,10 @@ class DocuCallable extends Callable { not this.getLocation() = this.getDeclaringType().getLocation() } + /** Holds if the Javadoc for this callable contains a minimum of a few characters of text. */ predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) } + /** Gets a string to identify whether this callable is a "method" or a "constructor". */ string toMethodOrConstructorString() { this instanceof Method and result = "method" or diff --git a/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll b/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll index e27c5f08157..87676170b2c 100644 --- a/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll +++ b/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll @@ -1,5 +1,8 @@ +/** Provides classes and predicates related to Java naming conventions. */ + import java +/** A field that is both `static` and `final`. */ class ConstantField extends Field { ConstantField() { this.isStatic() and diff --git a/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll b/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll index da880f7d4f7..473ac67b6c3 100644 --- a/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll +++ b/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Maven dependencies. */ + import java import semmle.code.xml.MavenPom diff --git a/java/ql/src/Compatibility/JDK9/JdkInternals.qll b/java/ql/src/Compatibility/JDK9/JdkInternals.qll index 70803d9395d..5e65a42ed82 100644 --- a/java/ql/src/Compatibility/JDK9/JdkInternals.qll +++ b/java/ql/src/Compatibility/JDK9/JdkInternals.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying unsupported JDK-internal APIs. + */ + /** * Provides a QL encoding of the list of unsupported JDK-internal APIs at: * diff --git a/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll b/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll index 907765c454f..fa7eb3cc12d 100644 --- a/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll +++ b/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying suggested replacements for unsupported JDK-internal APIs. + */ + /** * Provides a QL encoding of the suggested replacements for unsupported JDK-internal APIs listed at: * diff --git a/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql b/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql index 600257d1c60..0d4f56eb764 100644 --- a/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql +++ b/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql @@ -17,10 +17,7 @@ import semmle.code.java.Statement /** An expression that is used as a condition. */ class BooleanExpr extends Expr { BooleanExpr() { - exists(IfStmt s | s.getCondition() = this) or - exists(ForStmt s | s.getCondition() = this) or - exists(WhileStmt s | s.getCondition() = this) or - exists(DoStmt s | s.getCondition() = this) or + exists(ConditionalStmt s | s.getCondition() = this) or exists(ConditionalExpr s | s.getCondition() = this) } } diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index 2572d91cb99..cd5c34352d8 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -1,50 +1,8 @@ /** Definitions used by the queries for database query injection. */ -import semmle.code.java.Expr +import java import semmle.code.java.dataflow.FlowSources -import semmle.code.java.frameworks.android.SQLite -import semmle.code.java.frameworks.javaee.Persistence -import semmle.code.java.frameworks.SpringJdbc -import semmle.code.java.frameworks.MyBatis -import semmle.code.java.frameworks.Hibernate - -/** A sink for database query language injection vulnerabilities. */ -abstract class QueryInjectionSink extends DataFlow::ExprNode { } - -/** A sink for SQL injection vulnerabilities. */ -class SqlInjectionSink extends QueryInjectionSink { - SqlInjectionSink() { - this.getExpr() instanceof SqlExpr - or - exists(MethodAccess ma, Method m, int index | - ma.getMethod() = m and - ma.getArgument(index) = this.getExpr() - | - index = m.(SQLiteRunner).sqlIndex() - or - m instanceof BatchUpdateVarargsMethod - or - index = 0 and jdbcSqlMethod(m) - or - index = 0 and mybatisSqlMethod(m) - or - index = 0 and hibernateSqlMethod(m) - ) - } -} - -/** A sink for Java Persistence Query Language injection vulnerabilities. */ -class PersistenceQueryInjectionSink extends QueryInjectionSink { - PersistenceQueryInjectionSink() { - // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager` - exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.getExpr() | - call.getMethod() = em.getACreateQueryMethod() or - call.getMethod() = em.getACreateNativeQueryMethod() - // note: `createNamedQuery` is safe, as it takes only the query name, - // and named queries can only be constructed using constants as the query text - ) - } -} +import semmle.code.java.security.QueryInjection private class QueryInjectionFlowConfig extends TaintTracking::Configuration { QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" } diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql index e721cb7fba6..1f92b7acbbc 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql @@ -40,7 +40,7 @@ class UncontrolledStringBuilderSourceFlowConfig extends TaintTracking::Configura from QueryInjectionSink query, Expr uncontrolled where ( - builtFromUncontrolledConcat(query.getExpr(), uncontrolled) + builtFromUncontrolledConcat(query.asExpr(), uncontrolled) or exists(StringBuilderVar sbv, UncontrolledStringBuilderSourceFlowConfig conf | uncontrolledStringBuilderQuery(sbv, uncontrolled) and diff --git a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 384c24752cc..6a2fbbfadba 100644 --- a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -21,7 +21,7 @@ private class ShortStringLiteral extends StringLiteral { class BrokenAlgoLiteral extends ShortStringLiteral { BrokenAlgoLiteral() { - getValue().regexpMatch(algorithmBlacklistRegex()) and + getValue().regexpMatch(getInsecureAlgorithmRegex()) and // Exclude German and French sentences. not getValue().regexpMatch(".*\\p{IsLowercase} des \\p{IsLetter}.*") } diff --git a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql index d8d4d7e3650..efcd01548d8 100644 --- a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql @@ -25,9 +25,9 @@ class InsecureAlgoLiteral extends ShortStringLiteral { // Algorithm identifiers should be at least two characters. getValue().length() > 1 and exists(string s | s = getLiteral() | - not s.regexpMatch(algorithmWhitelistRegex()) and + not s.regexpMatch(getSecureAlgorithmRegex()) and // Exclude results covered by another query. - not s.regexpMatch(algorithmBlacklistRegex()) + not s.regexpMatch(getInsecureAlgorithmRegex()) ) } } diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql index 0249051820e..455f6add626 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import UrlRedirect +import semmle.code.java.security.UrlRedirect import DataFlow::PathGraph class UrlRedirectConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql index 5f642114530..e060d15ab9f 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import UrlRedirect +import semmle.code.java.security.UrlRedirect import DataFlow::PathGraph class UrlRedirectLocalConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java b/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java new file mode 100644 index 00000000000..7528311bc4b --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java @@ -0,0 +1,10 @@ +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.BasicAWSCredentials; + +public class HardcodedAWSCredentials { + public static void main(String[] args) { + //Hardcoded credentials for connecting to AWS services + //To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead + AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); //sensitive call + } +} diff --git a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll index d4611b53575..56072496293 100644 --- a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll +++ b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll @@ -129,7 +129,8 @@ private predicate javaApiCallablePasswordParam(string s) { s = "sun.tools.jconsole.ProxyClient;ProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" + s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" } /** @@ -200,7 +201,8 @@ private predicate javaApiCallableUsernameParam(string s) { s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);1" or s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, String);1" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" + s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" } /** diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java index 12891b56e17..ccb48687919 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java @@ -1,9 +1,9 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; public void serve(String ip, int port, String user, int timeout) { // ... @@ -20,17 +20,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; // Magic number is replaced by named constant + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; // Magic number is replaced by named constant public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'TIMEOUT' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java index e3cdaa5cb80..5cb0eaa1f10 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java @@ -1,9 +1,9 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... @@ -20,17 +20,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public int USERNAME = "test"; // Magic string is replaced by named constant - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final int USERNAME = "test"; // Magic string is replaced by named constant + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'USERNAME' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java index beb2916613b..075d6836a3b 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java @@ -1,19 +1,19 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - int internal_port = 8080; // AVOID: Magic number + int internalPort = 8080; // AVOID: Magic number - new MagicConstants().serve(IP, internal_port, USERNAME, TIMEOUT); + new MagicConstants().serve(IP, internalPort, USERNAME, TIMEOUT); } } @@ -21,17 +21,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'PORT' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp index 0dc6679535e..ea7f23e8e8c 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp @@ -35,7 +35,7 @@ update if the requirements change, because you have to update the number in only -

    The following example shows a magic number internal_port. This should be replaced by +

    The following example shows a magic number internalPort. This should be replaced by the existing named constant, as shown in the fixed version.

    diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java index b4b7c116e73..e2a6ee33f85 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java @@ -1,19 +1,19 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - String internal_ip = "127.0.0.1"; // AVOID: Magic string + String internalIp = "127.0.0.1"; // AVOID: Magic string - new MagicConstants().serve(internal_ip, PORT, USERNAME, TIMEOUT); + new MagicConstants().serve(internalIp, PORT, USERNAME, TIMEOUT); } } @@ -21,17 +21,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); //Use 'IP' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp index 1a6aa84b134..f2d4c86d8c7 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp @@ -35,7 +35,7 @@ update if the requirements change, because you have to update the string in only -

    The following example shows a magic string internal_ip. This should be replaced by +

    The following example shows a magic string internalIp. This should be replaced by the existing named constant, as shown in the fixed version.

    diff --git a/java/ql/src/codeql-suites/java-lgtm-full.qls b/java/ql/src/codeql-suites/java-lgtm-full.qls index e740d492f72..59b7c192e68 100644 --- a/java/ql/src/codeql-suites/java-lgtm-full.qls +++ b/java/ql/src/codeql-suites/java-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-java - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references \ No newline at end of file diff --git a/java/ql/src/codeql-suites/java-security-and-quality.qls b/java/ql/src/codeql-suites/java-security-and-quality.qls new file mode 100644 index 00000000000..1709789eb75 --- /dev/null +++ b/java/ql/src/codeql-suites/java-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for Java +- qlpack: codeql-java +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/java/ql/src/codeql-suites/java-security-extended.qls b/java/ql/src/codeql-suites/java-security-extended.qls new file mode 100644 index 00000000000..df10997bb38 --- /dev/null +++ b/java/ql/src/codeql-suites/java-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for Java +- qlpack: codeql-java +- apply: security-extended-selectors.yml + from: codeql-suite-helpers diff --git a/java/ql/src/default.qll b/java/ql/src/default.qll index 69104d35b85..79ed05a7c37 100644 --- a/java/ql/src/default.qll +++ b/java/ql/src/default.qll @@ -1 +1,3 @@ +/** DEPRECATED: use `java.qll` instead. */ + import java diff --git a/java/ql/src/definitions.ql b/java/ql/src/definitions.ql index d02a8d931b9..cb9ca932bcc 100644 --- a/java/ql/src/definitions.ql +++ b/java/ql/src/definitions.ql @@ -6,194 +6,8 @@ * @id java/jump-to-definition */ -import java - -/** - * Restricts the location of a method access to the method identifier only, - * excluding its qualifier, type arguments and arguments. - * - * If there is any whitespace between the method identifier and its first argument, - * or between the method identifier and its qualifier (or last type argument, if any), - * the location may be slightly inaccurate and include such whitespace, - * but it should suffice for the purpose of avoiding overlapping definitions. - */ -class LocationOverridingMethodAccess extends MethodAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() | - exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) | - sl = elRef and - sc = ecRef - getMethod().getName().length() + 1 and - el = elRef and - ec = ecRef - ) - ) - or - not exists(MemberRefExpr e | e.getReferencedCallable() = getMethod()) and - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - ( - if exists(getTypeArgument(_)) - then - exists(Location locTypeArg | - locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation() - | - sl = locTypeArg.getEndLine() and - sc = locTypeArg.getEndColumn() + 2 - ) - else ( - if exists(getQualifier()) - then - // Note: this needs to be the original (full) location of the qualifier, not the modified one. - exists(Location locQual | locQual = getQualifier().getLocation() | - sl = locQual.getEndLine() and - sc = locQual.getEndColumn() + 2 - ) - else ( - sl = slSuper and - sc = scSuper - ) - ) - ) and - ( - if getNumArgument() > 0 - then - // Note: this needs to be the original (full) location of the first argument, not the modified one. - exists(Location locArg | locArg = getArgument(0).getLocation() | - el = locArg.getStartLine() and - ec = locArg.getStartColumn() - 2 - ) - else ( - el = elSuper and - ec = ecSuper - 2 - ) - ) - ) - } -} - -/** - * Restricts the location of a type access to exclude - * the type arguments and qualifier, if any. - */ -class LocationOverridingTypeAccess extends TypeAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - ( - if exists(getQualifier()) - then - // Note: this needs to be the original (full) location of the qualifier, not the modified one. - exists(Location locQual | locQual = getQualifier().getLocation() | - sl = locQual.getEndLine() and - sc = locQual.getEndColumn() + 2 - ) - else ( - sl = slSuper and - sc = scSuper - ) - ) and - ( - if exists(getTypeArgument(_)) - then - // Note: this needs to be the original (full) location of the first type argument, not the modified one. - exists(Location locArg | locArg = getTypeArgument(0).getLocation() | - el = locArg.getStartLine() and - ec = locArg.getStartColumn() - 2 - ) - else ( - el = elSuper and - ec = ecSuper - ) - ) - ) - } -} - -/** - * Restricts the location of a field access to the name of the accessed field only, - * excluding its qualifier. - */ -class LocationOverridingFieldAccess extends FieldAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - super.hasLocationInfo(path, _, _, el, ec) and - sl = el and - sc = ec - getField().getName().length() + 1 - } -} - -/** - * Restricts the location of a single-type-import declaration to the name of the imported type only, - * excluding the `import` keyword and the package name. - */ -class LocationOverridingImportType extends ImportType { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - el = elSuper and - ec = ecSuper - 1 and - sl = el and - sc = ecSuper - getImportedType().getName().length() - ) - } -} - -/** - * Restricts the location of a single-static-import declaration to the name of the imported member(s) only, - * excluding the `import` keyword and the package name. - */ -class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - el = elSuper and - ec = ecSuper - 1 and - sl = el and - sc = ecSuper - getName().length() - ) - } -} - -Element definition(Element e, string kind) { - e.(MethodAccess).getMethod().getSourceDeclaration() = result and - kind = "M" and - not result instanceof InitializerMethod - or - e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T" - or - exists(Variable v | v = e.(VarAccess).getVariable() | - result = v.(Field).getSourceDeclaration() or - result = v.(Parameter).getSourceDeclaration() or - result = v.(LocalVariableDecl) - ) and - kind = "V" - or - e.(ImportType).getImportedType() = result and kind = "I" - or - e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I" -} - -predicate dummyVarAccess(VarAccess va) { - exists(AssignExpr ae, InitializerMethod im | - ae.getDest() = va and - ae.getParent() = im.getBody().getAChild() - ) -} - -predicate dummyTypeAccess(TypeAccess ta) { - exists(FunctionalExpr e | - e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*() - ) -} +import definitions from Element e, Element def, string kind -where - def = definition(e, kind) and - def.fromSource() and - e.fromSource() and - not dummyVarAccess(e) and - not dummyTypeAccess(e) +where def = definitionOf(e, kind) select e, def, kind diff --git a/java/ql/src/definitions.qll b/java/ql/src/definitions.qll new file mode 100644 index 00000000000..a91e0026e91 --- /dev/null +++ b/java/ql/src/definitions.qll @@ -0,0 +1,212 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import java + +/** + * Restricts the location of a method access to the method identifier only, + * excluding its qualifier, type arguments and arguments. + * + * If there is any whitespace between the method identifier and its first argument, + * or between the method identifier and its qualifier (or last type argument, if any), + * the location may be slightly inaccurate and include such whitespace, + * but it should suffice for the purpose of avoiding overlapping definitions. + */ +private class LocationOverridingMethodAccess extends MethodAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() | + exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) | + sl = elRef and + sc = ecRef - getMethod().getName().length() + 1 and + el = elRef and + ec = ecRef + ) + ) + or + not exists(MemberRefExpr e | e.getReferencedCallable() = getMethod()) and + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + ( + if exists(getTypeArgument(_)) + then + exists(Location locTypeArg | + locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation() + | + sl = locTypeArg.getEndLine() and + sc = locTypeArg.getEndColumn() + 2 + ) + else ( + if exists(getQualifier()) + then + // Note: this needs to be the original (full) location of the qualifier, not the modified one. + exists(Location locQual | locQual = getQualifier().getLocation() | + sl = locQual.getEndLine() and + sc = locQual.getEndColumn() + 2 + ) + else ( + sl = slSuper and + sc = scSuper + ) + ) + ) and + ( + if getNumArgument() > 0 + then + // Note: this needs to be the original (full) location of the first argument, not the modified one. + exists(Location locArg | locArg = getArgument(0).getLocation() | + el = locArg.getStartLine() and + ec = locArg.getStartColumn() - 2 + ) + else ( + el = elSuper and + ec = ecSuper - 2 + ) + ) + ) + } +} + +/** + * Restricts the location of a type access to exclude + * the type arguments and qualifier, if any. + */ +private class LocationOverridingTypeAccess extends TypeAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + ( + if exists(getQualifier()) + then + // Note: this needs to be the original (full) location of the qualifier, not the modified one. + exists(Location locQual | locQual = getQualifier().getLocation() | + sl = locQual.getEndLine() and + sc = locQual.getEndColumn() + 2 + ) + else ( + sl = slSuper and + sc = scSuper + ) + ) and + ( + if exists(getTypeArgument(_)) + then + // Note: this needs to be the original (full) location of the first type argument, not the modified one. + exists(Location locArg | locArg = getTypeArgument(0).getLocation() | + el = locArg.getStartLine() and + ec = locArg.getStartColumn() - 2 + ) + else ( + el = elSuper and + ec = ecSuper + ) + ) + ) + } +} + +/** + * Restricts the location of a field access to the name of the accessed field only, + * excluding its qualifier. + */ +private class LocationOverridingFieldAccess extends FieldAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + super.hasLocationInfo(path, _, _, el, ec) and + sl = el and + sc = ec - getField().getName().length() + 1 + } +} + +/** + * Restricts the location of a single-type-import declaration to the name of the imported type only, + * excluding the `import` keyword and the package name. + */ +private class LocationOverridingImportType extends ImportType { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + el = elSuper and + ec = ecSuper - 1 and + sl = el and + sc = ecSuper - getImportedType().getName().length() + ) + } +} + +/** + * Restricts the location of a single-static-import declaration to the name of the imported member(s) only, + * excluding the `import` keyword and the package name. + */ +private class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + el = elSuper and + ec = ecSuper - 1 and + sl = el and + sc = ecSuper - getName().length() + ) + } +} + +private Element definition(Element e, string kind) { + e.(MethodAccess).getMethod().getSourceDeclaration() = result and + kind = "M" and + not result instanceof InitializerMethod + or + e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T" + or + exists(Variable v | v = e.(VarAccess).getVariable() | + result = v.(Field).getSourceDeclaration() or + result = v.(Parameter).getSourceDeclaration() or + result = v.(LocalVariableDecl) + ) and + kind = "V" + or + e.(ImportType).getImportedType() = result and kind = "I" + or + e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I" +} + +private predicate dummyVarAccess(VarAccess va) { + exists(AssignExpr ae, InitializerMethod im | + ae.getDest() = va and + ae.getParent() = im.getBody().getAChild() + ) +} + +private predicate dummyTypeAccess(TypeAccess ta) { + exists(FunctionalExpr e | + e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*() + ) +} + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + * + * The `kind` is a string representing what kind of use it is: + * - `"M"` for function and method calls + * - `"T"` for uses of types + * - `"V"` for variable accesses + * - `"I"` for import directives + */ +Element definitionOf(Element e, string kind) { + result = definition(e, kind) and + result.fromSource() and + e.fromSource() and + not dummyVarAccess(e) and + not dummyTypeAccess(e) +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java new file mode 100644 index 00000000000..e1f7354b912 --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java @@ -0,0 +1,18 @@ +public static void main(String[] args) { + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); + + String password = "Pass@0rd"; + + // BAD: user password is written to debug log + logger.debug("User password is "+password); + } + + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); + + String password = "Pass@0rd"; + + // GOOD: user password is never written to debug log + } +} diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp new file mode 100644 index 00000000000..b6261ae900f --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp @@ -0,0 +1,26 @@ + + + + +

    Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information is written to logs without properly set logging levels, it is accessible to potential attackers who can use it to gain access to +file storage.

    +
    + + +

    Do not write secrets into the log files and enforce proper logging level control.

    +
    + + +

    The following example shows two ways of logging sensitive information. In the 'BAD' case, +the credentials are simply written to a debug log. In the 'GOOD' case, the credentials are never written to debug logs.

    + +
    + + +
  • +OWASP Logging Guide +
  • +
    +
    diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql new file mode 100644 index 00000000000..d42ce25a46f --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -0,0 +1,66 @@ +/** + * @id java/sensitiveinfo-in-logfile + * @name Insertion of sensitive information into log files + * @description Writing sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information. + * @kind path-problem + * @tags security + * external/cwe-532 + */ + +import java +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + +/** + * Gets a regular expression for matching names of variables that indicate the value being held is a credential + */ +private string getACredentialRegex() { + result = "(?i).*challenge|pass(wd|word|code|phrase)(?!.*question).*" or + result = "(?i)(.*username|url).*" +} + +/** Variable keeps sensitive information judging by its name * */ +class CredentialExpr extends Expr { + CredentialExpr() { + exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex())) + } +} + +/** Class of popular logging utilities * */ +class LoggerType extends RefType { + LoggerType() { + this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J + this.hasQualifiedName("org.slf4j", "Logger") or //SLF4j and Gradle Logging + this.hasQualifiedName("org.jboss.logging", "BasicLogger") //JBoss Logging + } +} + +predicate isSensitiveLoggingSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod().getDeclaringType() instanceof LoggerType and + ( + ma.getMethod().hasName("debug") or + ma.getMethod().hasName("trace") or + ma.getMethod().hasName("debugf") + ) and //Check low priority log levels which are more likely to be real issues to reduce false positives + sink.asExpr() = ma.getAnArgument() + ) +} + +class LoggerConfiguration extends DataFlow::Configuration { + LoggerConfiguration() { this = "Logger Configuration" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr } + + override predicate isSink(DataFlow::Node sink) { isSensitiveLoggingSink(sink) } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + TaintTracking::localTaintStep(node1, node2) + } +} + +from LoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Outputting $@ to log.", source.getNode(), + "sensitive information" diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java new file mode 100644 index 00000000000..1c06f05bc7e --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java @@ -0,0 +1,17 @@ +public boolean shouldOverrideUrlLoading(WebView view, String url) { + { + Uri uri = Uri.parse(url); + // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification + if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { + return false; + } + } + + { + Uri uri = Uri.parse(url); + // GOOD: full domain match + if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { + return false; + } + } +} diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp new file mode 100644 index 00000000000..850e9f3fa9d --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -0,0 +1,28 @@ + + + + +

    Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.

    +
    + + +

    Verify the whole host and domain (FQDN) or check endsWith dot+domain.

    +
    + + +

    The following example shows two ways of verifying host domain. In the 'BAD' case, +verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.

    + +
    + + +
  • +Common Android app vulnerabilities from Sebastian Porst of Google +
  • +
  • +Common Android app vulnerabilities from bugcrowd +
  • +
    +
    diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql new file mode 100644 index 00000000000..46541d28698 --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -0,0 +1,97 @@ +/** + * @id java/incorrect-url-verification + * @name Incorrect URL verification + * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. + * @kind problem + * @tags security + * external/cwe-939 + */ + +import java + +/** + * The Java class `android.R.string` specific to Android applications, which contains references to application specific resources defined in /res/values/strings.xml. + * For example, ...example.com... in the application com.example.android.web can be referred as R.string.host with the type com.example.android.web.R$string + */ +class AndroidRString extends RefType { + AndroidRString() { this.hasQualifiedName(_, "R$string") } +} + +/** + * The Java class `android.net.Uri` and `java.net.URL`. + */ +class Uri extends RefType { + Uri() { + hasQualifiedName("android.net", "Uri") or + hasQualifiedName("java.net", "URL") + } +} + +/** + * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`. + */ +class UriGetHostMethod extends Method { + UriGetHostMethod() { + getDeclaringType() instanceof Uri and + hasName("getHost") and + getNumberOfParameters() = 0 + } +} + +/** + * The method access with incorrect string comparision + */ +class HostVerificationMethodAccess extends MethodAccess { + HostVerificationMethodAccess() { + ( + this.getMethod().hasName("endsWith") or + this.getMethod().hasName("contains") or + this.getMethod().hasName("indexOf") + ) and + this.getMethod().getNumberOfParameters() = 1 and + ( + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." //string constant comparison e.g. uri.getHost().endsWith("example.com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) + or + exists(MethodAccess ma, Method m, Field f | + this.getArgument(0) = ma and + ma.getMethod() = m and + m.hasName("getString") and + m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and + ma.getArgument(0).(FieldRead).getField() = f and + f.getDeclaringType() instanceof AndroidRString + ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) + or + this + .getArgument(0) + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) + ) + } +} + +from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma +where hma.getQualifier() = uma and uma.getMethod() = um +select hma, "Method has potentially $@ ", hma.getArgument(0), "improper URL verification" diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll index 658983f2437..c1ef873b1fa 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -22,8 +22,7 @@ class TypeAuthorizedUrl extends Class { } /** - * The class - * `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. */ class TypeAbstractRequestMatcherRegistry extends Class { TypeAbstractRequestMatcherRegistry() { @@ -34,38 +33,44 @@ class TypeAbstractRequestMatcherRegistry extends Class { } /** - * The class - * `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`. + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. */ -class TypeEndpointRequestMatcher extends Class { - TypeEndpointRequestMatcher() { +class TypeEndpointRequest extends Class { + TypeEndpointRequest() { this .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", - "EndpointRequest$EndpointRequestMatcher") + "EndpointRequest") + } +} + +/** A call to `EndpointRequest.toAnyEndpoint` method. */ +class ToAnyEndpointCall extends MethodAccess { + ToAnyEndpointCall() { + getMethod().hasName("toAnyEndpoint") and + getMethod().getDeclaringType() instanceof TypeEndpointRequest } } /** - * A call to `HttpSecurity.requestMatcher` method with argument of type - * `EndpointRequestMatcher`. + * A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`. */ class RequestMatcherCall extends MethodAccess { RequestMatcherCall() { getMethod().hasName("requestMatcher") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).getType() instanceof TypeEndpointRequestMatcher + getArgument(0) instanceof ToAnyEndpointCall } } /** - * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to - * `EndpointRequestMatcher` type. + * A call to `HttpSecurity.requestMatchers` method with lambda argument + * `RequestMatcher.toAnyEndpoint()`. */ class RequestMatchersCall extends MethodAccess { RequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher + getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall } } @@ -92,9 +97,6 @@ class PermitAllCall extends MethodAccess { or // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall - or - // http.authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof VarAccess | // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) @@ -117,6 +119,22 @@ class PermitAllCall extends MethodAccess { this.getQualifier() = anyRequestCall ) ) + or + exists(AuthorizeRequestsCall authorizeRequestsCall | + // http.authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof VarAccess + | + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and + this.getQualifier() instanceof RegistryRequestMatchersCall + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + authorizeRequestsCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and + this.getQualifier() = registryRequestMatchersCall + ) + ) } } @@ -129,13 +147,13 @@ class AnyRequestCall extends MethodAccess { } /** - * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type - * `EndpointRequestMatcher`. + * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument + * `RequestMatcher.toAnyEndpoint()`. */ class RegistryRequestMatchersCall extends MethodAccess { RegistryRequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and - getAnArgument().getType() instanceof TypeEndpointRequestMatcher + getAnArgument() instanceof ToAnyEndpointCall } } diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..ce75fdab6be --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java @@ -0,0 +1,21 @@ +import javax.naming.Context; +import javax.naming.InitialContext; + +public void jndiLookup(HttpServletRequest request) throws NamingException { + String name = request.getParameter("name"); + + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.PROVIDER_URL, "rmi://trusted-server:1099"); + InitialContext ctx = new InitialContext(env); + + // BAD: User input used in lookup + ctx.lookup(name); + + // GOOD: The name is validated before being used in lookup + if (isValid(name)) { + ctx.lookup(name); + } else { + // Reject the request + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp new file mode 100644 index 00000000000..d1d7b2ba51f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp @@ -0,0 +1,36 @@ + + + +

    The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that allows +Java software clients to discover and look up data and resources (in the form of Java objects) via +a name. If the name being used to look up the data is controlled by the user, it can point to a +malicious server, which can return an arbitrary object. In the worst case, this can allow remote +code execution.

    +
    + + +

    The general recommendation is to not pass untrusted data to the InitialContext.lookup + method. If the name being used to look up the object must be provided by the user, make +sure that it's not in the form of an absolute URL or that it's the URL pointing to a trused server. +

    +
    + + +

    In the following examples, the code accepts a name from the user, which it uses to look up an +object.

    + +

    In the first example, the user provided name is used to look up an object.

    + +

    The second example validates the name before using it to look up an object.

    + + +
    + + +
  • Oracle: Java Naming and Directory Interface (JNDI).
  • +
  • Black Hat materials: A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land.
  • +
  • Veracode: Exploiting JNDI Injections in Java.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql new file mode 100644 index 00000000000..2b1af37dcae --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql @@ -0,0 +1,21 @@ +/** + * @name JNDI lookup with user-controlled name + * @description Doing a JNDI lookup with user-controlled name can lead to download an untrusted + * object and to execution of arbitrary code. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/jndi-injection + * @tags security + * external/cwe/cwe-074 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import JndiInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll new file mode 100644 index 00000000000..6cca28872a3 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -0,0 +1,261 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import experimental.semmle.code.java.frameworks.Jndi +import experimental.semmle.code.java.frameworks.spring.SpringJndi +import semmle.code.java.frameworks.SpringLdap +import experimental.semmle.code.java.frameworks.Shiro + +/** + * A taint-tracking configuration for unvalidated user input that is used in JNDI lookup. + */ +class JndiInjectionFlowConfig extends TaintTracking::Configuration { + JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + nameStep(node1, node2) or + jmxServiceUrlStep(node1, node2) or + jmxConnectorStep(node1, node2) or + rmiConnectorStep(node1, node2) + } +} + +/** The class `java.util.Hashtable`. */ +class TypeHashtable extends Class { + TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") } +} + +/** The class `javax.naming.directory.SearchControls`. */ +class TypeSearchControls extends Class { + TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") } +} + +/** + * The interface `org.springframework.ldap.core.LdapOperations` (spring-ldap 1.2.x and newer) or + * `org.springframework.ldap.LdapOperations` (spring-ldap 1.1.x). + */ +class TypeSpringLdapOperations extends Interface { + TypeSpringLdapOperations() { + this.hasQualifiedName("org.springframework.ldap.core", "LdapOperations") or + this.hasQualifiedName("org.springframework.ldap", "LdapOperations") + } +} + +/** + * The interface `org.springframework.ldap.core.ContextMapper` (spring-ldap 1.2.x and newer) or + * `org.springframework.ldap.ContextMapper` (spring-ldap 1.1.x). + */ +class TypeSpringContextMapper extends Interface { + TypeSpringContextMapper() { + this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or + this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap", "ContextMapper") + } +} + +/** The interface `javax.management.remote.JMXConnector`. */ +class TypeJMXConnector extends Interface { + TypeJMXConnector() { this.hasQualifiedName("javax.management.remote", "JMXConnector") } +} + +/** The class `javax.management.remote.rmi.RMIConnector`. */ +class TypeRMIConnector extends Class { + TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") } +} + +/** The class `javax.management.remote.JMXConnectorFactory`. */ +class TypeJMXConnectorFactory extends Class { + TypeJMXConnectorFactory() { + this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory") + } +} + +/** The class `javax.management.remote.JMXServiceURL`. */ +class TypeJMXServiceURL extends Class { + TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") } +} + +/** The interface `javax.naming.Context`. */ +class TypeNamingContext extends Interface { + TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") } +} + +/** + * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`, + * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`. + */ +predicate jndiSinkMethod(Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeInitialContext and + ( + m.hasName("lookup") or + m.hasName("lookupLink") or + m.hasName("doLookup") or + m.hasName("rename") or + m.hasName("list") or + m.hasName("listBindings") + ) and + index = 0 +} + +/** + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Spring's `JndiTemplate`. + */ +predicate springJndiTemplateSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeSpringJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupContext`, + * `findByDn`, `rename`, `list`, `listBindings`, `unbind`, `search` or `searchForObject` method + * from Spring's `LdapOperations`. + */ +predicate springLdapTemplateSinkMethod(MethodAccess ma, Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeSpringLdapOperations and + ( + m.hasName("lookup") + or + m.hasName("lookupContext") + or + m.hasName("findByDn") + or + m.hasName("rename") + or + m.hasName("list") + or + m.hasName("listBindings") + or + m.hasName("unbind") and ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true + or + m.getName().matches("search%") and + m.getParameterType(m.getNumberOfParameters() - 1) instanceof TypeSpringContextMapper and + not m.getAParamType() instanceof TypeSearchControls + or + m.hasName("search") and ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true + ) and + index = 0 +} + +/** + * Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Shiro's `JndiTemplate`. + */ +predicate shiroSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeShiroJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** + * `JMXConnectorFactory` sink for JNDI injection vulnerabilities, i.e. 1st argument to `connect` + * method from `JMXConnectorFactory`. + */ +predicate jmxConnectorFactorySinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeJMXConnectorFactory and + m.hasName("connect") and + index = 0 +} + +/** + * Tainted value passed to env `Hashtable` as the provider URL, i.e. + * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`. + */ +predicate providerUrlEnv(MethodAccess ma, Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeHashtable and + (m.hasName("put") or m.hasName("setProperty")) and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" + or + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName("PROVIDER_URL") and + f.getDeclaringType() instanceof TypeNamingContext + ) + ) and + index = 1 +} + +/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ +predicate jndiInjectionSinkMethod(MethodAccess ma, Method m, int index) { + jndiSinkMethod(m, index) or + springJndiTemplateSinkMethod(m, index) or + springLdapTemplateSinkMethod(ma, m, index) or + shiroSinkMethod(m, index) or + jmxConnectorFactorySinkMethod(m, index) or + providerUrlEnv(ma, m, index) +} + +/** A data flow sink for unvalidated user input that is used in JNDI lookup. */ +class JndiInjectionSink extends DataFlow::ExprNode { + JndiInjectionSink() { + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + ma.getArgument(index) = this.getExpr() and + jndiInjectionSinkMethod(ma, m, index) + ) + or + exists(MethodAccess ma, Method m | + ma.getMethod() = m and + ma.getQualifier() = this.getExpr() and + m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and + m.hasName("connect") + ) + } +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName` or + * `CompoundName`, i.e. `new CompositeName(tainted)` or `new CompoundName(tainted)`. + */ +predicate nameStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TypeCompositeName or + cc.getConstructedType() instanceof TypeCompoundName + | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`, + * i.e. `new JMXServiceURL(tainted)`. + */ +predicate jmxServiceUrlStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeJMXServiceURL | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and + * `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`. + */ +predicate jmxConnectorStep(ExprNode n1, ExprNode n2) { + exists(MethodAccess ma, Method m | n1.asExpr() = ma.getArgument(0) and n2.asExpr() = ma | + ma.getMethod() = m and + m.getDeclaringType() instanceof TypeJMXConnectorFactory and + m.hasName("newJMXConnector") + ) +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and + * `RMIConnector`, i.e. `new RMIConnector(tainted)`. + */ +predicate rmiConnectorStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeRMIConnector | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp new file mode 100644 index 00000000000..d68d298b5f5 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp @@ -0,0 +1,38 @@ + + + + +

    +MVEL is an expression language based on Java-syntax. +The language offers many features +including invocation of methods available in the JVM. +If a MVEL expression is built using attacker-controlled data, +and then evaluated, then it may allow the attacker to run arbitrary code. +

    +
    + + +

    +Including user input in a MVEL expression should be avoided. +

    +
    + + +

    +The following example uses untrusted data to build a MVEL expression +and then runs it in the default powerfull context. +

    + +
    + + +
  • + MVEL Documentation: + Language Guide for 2.0. +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql new file mode 100644 index 00000000000..d32c33c343c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Expression language injection (MVEL) + * @description Evaluation of a user-controlled MVEL expression + * may lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/mvel-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import MvelInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, MvelInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "MVEL injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll new file mode 100644 index 00000000000..a6cf891330f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -0,0 +1,367 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a MVEL expression. + */ +class MvelInjectionConfig extends TaintTracking::Configuration { + MvelInjectionConfig() { this = "MvelInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof MvelEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + expressionCompilationStep(node1, node2) or + createExpressionCompilerStep(node1, node2) or + expressionCompilerCompileStep(node1, node2) or + createCompiledAccExpressionStep(node1, node2) or + scriptCompileStep(node1, node2) or + createMvelCompiledScriptStep(node1, node2) or + templateCompileStep(node1, node2) or + createTemplateCompilerStep(node1, node2) + } +} + +/** + * A sink for EL injection vulnerabilities via MVEL, + * i.e. methods that run evaluation of a MVEL expression. + */ +class MvelEvaluationSink extends DataFlow::ExprNode { + MvelEvaluationSink() { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + ( + m instanceof MvelEvalMethod or + m instanceof TemplateRuntimeEvaluationMethod + ) and + ma.getArgument(0) = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelScriptEngineEvaluationMethod and + ma.getArgument(0) = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + ( + m instanceof ExecutableStatementEvaluationMethod or + m instanceof CompiledExpressionEvaluationMethod or + m instanceof CompiledAccExpressionEvaluationMethod or + m instanceof AccessorEvaluationMethod or + m instanceof CompiledScriptEvaluationMethod or + m instanceof MvelCompiledScriptEvaluationMethod + ) and + ma.getQualifier() = asExpr() + ) + or + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelRuntimeEvaluationMethod and + ma.getArgument(1) = asExpr() + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by callilng `MVEL.compileExpression(tainted)`. + */ +predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof MVEL and + m.hasName("compileExpression") and + ma.getAnArgument() = node1.asExpr() and + node2.asExpr() = ma + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `ExpressionCompiler`, + * i.e. `new ExpressionCompiler(tainted)`. + */ +predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof ExpressionCompiler and + cc = node2.asExpr() and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `CompiledAccExpression`, + * i.e. `new CompiledAccExpression(tainted, ...)`. + */ +predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof CompiledAccExpression and + cc = node2.asExpr() and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by calling `ExpressionCompiler.compile()`. + */ +predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof ExpressionCompiler and + m.hasName("compile") and + ma = node2.asExpr() and + ma.getQualifier() = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `MvelScriptEngine`, + * i.e. `engine.compile(tainted)` or `engine.compiledScript(tainted)`. + */ +predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof MvelScriptEngineCompilationMethod and + ma = node2.asExpr() and + ma.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `MvelCompiledScript`, + * i.e. `new MvelCompiledScript(engine, tainted)`. + */ +predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof MvelCompiledScript and + cc = node2.asExpr() and + cc.getArgument(1) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `TemplateCompiler`, + * i.e. `new TemplateCompiler(tainted)`. + */ +predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TemplateCompiler and + cc = node2.asExpr() and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `TemplateCompiler`, + * i.e. `compiler.compile()` or `TemplateCompiler.compileTemplate(tainted)`. + */ +predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileMethod and + ma.getQualifier() = node1.asExpr() and + ma = node2.asExpr() + ) + or + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileTemplateMethod and + ma = node2.asExpr() and + ma.getArgument(0) = node1.asExpr() + ) +} + +/** + * Methods in the MVEL class that evaluate a MVEL expression. + */ +class MvelEvalMethod extends Method { + MvelEvalMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("eval") or + hasName("executeExpression") or + hasName("evalToBoolean") or + hasName("evalToString") or + hasName("executeAllExpression") or + hasName("executeSetExpression") + ) + } +} + +/** + * Methods in `MVEL` class that compile a MVEL expression. + */ +class MvelCompileExpressionMethod extends Method { + MvelCompileExpressionMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("compileExpression") or + hasName("compileGetExpression") or + hasName("compileSetExpression") + ) + } +} + +/** + * Methods in `ExecutableStatement` that evaluate a MVEL expression. + */ +class ExecutableStatementEvaluationMethod extends Method { + ExecutableStatementEvaluationMethod() { + getDeclaringType() instanceof ExecutableStatement and + hasName("getValue") + } +} + +/** + * Methods in `CompiledExpression` that evaluate a MVEL expression. + */ +class CompiledExpressionEvaluationMethod extends Method { + CompiledExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledExpression and + hasName("getDirectValue") + } +} + +/** + * Methods in `CompiledAccExpression` that evaluate a MVEL expression. + */ +class CompiledAccExpressionEvaluationMethod extends Method { + CompiledAccExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledAccExpression and + hasName("getValue") + } +} + +/** + * Methods in `Accessor` that evaluate a MVEL expression. + */ +class AccessorEvaluationMethod extends Method { + AccessorEvaluationMethod() { + getDeclaringType() instanceof Accessor and + hasName("getValue") + } +} + +/** + * Methods in `MvelScriptEngine` that evaluate a MVEL expression. + */ +class MvelScriptEngineEvaluationMethod extends Method { + MvelScriptEngineEvaluationMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("eval") or hasName("evaluate")) + } +} + +/** + * Methods in `MvelScriptEngine` that compile a MVEL expression. + */ +class MvelScriptEngineCompilationMethod extends Method { + MvelScriptEngineCompilationMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("compile") or hasName("compiledScript")) + } +} + +/** + * Methods in `CompiledScript` that evaluate a MVEL expression. + */ +class CompiledScriptEvaluationMethod extends Method { + CompiledScriptEvaluationMethod() { + getDeclaringType() instanceof CompiledScript and + hasName("eval") + } +} + +/** + * Methods in `TemplateRuntime` that evaluate a MVEL template. + */ +class TemplateRuntimeEvaluationMethod extends Method { + TemplateRuntimeEvaluationMethod() { + getDeclaringType() instanceof TemplateRuntime and + (hasName("eval") or hasName("execute")) + } +} + +/** + * `TemplateCompiler.compile()` method compiles a MVEL template. + */ +class TemplateCompilerCompileMethod extends Method { + TemplateCompilerCompileMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compile") + } +} + +/** + * `TemplateCompiler.compileTemplate(tainted)` static method compiles a MVEL template. + */ +class TemplateCompilerCompileTemplateMethod extends Method { + TemplateCompilerCompileTemplateMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compileTemplate") + } +} + +/** + * Methods in `MvelCompiledScript` that evaluate a MVEL expression. + */ +class MvelCompiledScriptEvaluationMethod extends Method { + MvelCompiledScriptEvaluationMethod() { + getDeclaringType() instanceof MvelCompiledScript and + hasName("eval") + } +} + +/** + * Methods in `MVELRuntime` that evaluate a MVEL expression. + */ +class MvelRuntimeEvaluationMethod extends Method { + MvelRuntimeEvaluationMethod() { + getDeclaringType() instanceof MVELRuntime and + hasName("execute") + } +} + +class MVEL extends RefType { + MVEL() { hasQualifiedName("org.mvel2", "MVEL") } +} + +class ExpressionCompiler extends RefType { + ExpressionCompiler() { hasQualifiedName("org.mvel2.compiler", "ExpressionCompiler") } +} + +class ExecutableStatement extends RefType { + ExecutableStatement() { hasQualifiedName("org.mvel2.compiler", "ExecutableStatement") } +} + +class CompiledExpression extends RefType { + CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } +} + +class CompiledAccExpression extends RefType { + CompiledAccExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledAccExpression") } +} + +class Accessor extends RefType { + Accessor() { hasQualifiedName("org.mvel2.compiler", "Accessor") } +} + +class CompiledScript extends RefType { + CompiledScript() { hasQualifiedName("javax.script", "CompiledScript") } +} + +class MvelScriptEngine extends RefType { + MvelScriptEngine() { hasQualifiedName("org.mvel2.jsr223", "MvelScriptEngine") } +} + +class MvelCompiledScript extends RefType { + MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") } +} + +class TemplateRuntime extends RefType { + TemplateRuntime() { hasQualifiedName("org.mvel2.templates", "TemplateRuntime") } +} + +class TemplateCompiler extends RefType { + TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") } +} + +class MVELRuntime extends RefType { + MVELRuntime() { hasQualifiedName("org.mvel2", "MVELRuntime") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java new file mode 100644 index 00000000000..04dc4a5220f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java @@ -0,0 +1,12 @@ +public Object evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String string = reader.readLine(); + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(string); + SimpleEvaluationContext context + = SimpleEvaluationContext.forReadWriteDataBinding().build(); + return expression.getValue(context); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp new file mode 100644 index 00000000000..74bc1b21325 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp @@ -0,0 +1,56 @@ + + + + +

    +The Spring Expression Language (SpEL) is a powerful expression language +provided by Spring Framework. The language offers many features +including invocation of methods available in the JVM. +If a SpEL expression is built using attacker-controlled data, +and then evaluated in a powerful context, +then it may allow the attacker to run arbitrary code. +

    +

    +The SpelExpressionParser class parses a SpEL expression string +and returns an Expression instance +that can be then evaluated by calling one of its methods. +By default, an expression is evaluated in a powerful StandardEvaluationContext +that allows the expression to access other methods available in the JVM. +

    +
    + + +

    +In general, including user input in a SpEL expression should be avoided. +If user input must be included in the expression, +it should be then evaluated in a limited context +that doesn't allow arbitrary method invocation. +

    +
    + + +

    +The following example uses untrusted data to build a SpEL expression +and then runs it in the default powerfull context. +

    + + +

    +The next example shows how an untrusted SpEL expression can be run +in SimpleEvaluationContext that doesn't allow accessing arbitrary methods. +However, it's recommended to avoid using untrusted input in SpEL expressions. +

    + +
    + + +
  • + Spring Framework Reference Documentation: + Spring Expression Language (SpEL). +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql new file mode 100644 index 00000000000..d9914c4d512 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Expression language injection (Spring) + * @description Evaluation of a user-controlled Spring Expression Language (SpEL) expression + * may lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/spel-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import SpelInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, ExpressionInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "SpEL injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll new file mode 100644 index 00000000000..27e0ee463f6 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll @@ -0,0 +1,100 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import SpringFrameworkLib + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a SpEL expression. + */ +class ExpressionInjectionConfig extends TaintTracking::Configuration { + ExpressionInjectionConfig() { this = "ExpressionInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource or + source instanceof WebRequestSource + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + expressionParsingStep(node1, node2) or + springPropertiesStep(node1, node2) + } +} + +/** + * A sink for SpEL injection vulnerabilities, + * i.e. methods that run evaluation of a SpEL expression in a powerfull context. + */ +class ExpressionEvaluationSink extends DataFlow::ExprNode { + ExpressionEvaluationSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExpressionEvaluationMethod and + getExpr() = ma.getQualifier() and + not exists(SafeEvaluationContextFlowConfig config | + config.hasFlowTo(DataFlow::exprNode(ma.getArgument(0))) + ) + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that parses a SpEL expression, + * i.e. `parser.parseExpression(tainted)`. + */ +predicate expressionParsingStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType().getAnAncestor*() instanceof ExpressionParser and + m.hasName("parseExpression") and + ma.getAnArgument() = node1.asExpr() and + node2.asExpr() = ma + ) +} + +/** + * A configuration for safe evaluation context that may be used in expression evaluation. + */ +class SafeEvaluationContextFlowConfig extends DataFlow2::Configuration { + SafeEvaluationContextFlowConfig() { this = "SpelInjection::SafeEvaluationContextFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof SafeContextSource } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExpressionEvaluationMethod and + ma.getArgument(0) = sink.asExpr() + ) + } + + override int fieldFlowBranchLimit() { result = 0 } +} + +class SafeContextSource extends DataFlow::ExprNode { + SafeContextSource() { + isSimpleEvaluationContextConstructorCall(getExpr()) or + isSimpleEvaluationContextBuilderCall(getExpr()) + } +} + +/** + * Holds if `expr` constructs `SimpleEvaluationContext`. + */ +predicate isSimpleEvaluationContextConstructorCall(Expr expr) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof SimpleEvaluationContext and + cc = expr + ) +} + +/** + * Holds if `expr` builds `SimpleEvaluationContext` via `SimpleEvaluationContext.Builder`, + * e.g. `SimpleEvaluationContext.forReadWriteDataBinding().build()`. + */ +predicate isSimpleEvaluationContextBuilderCall(Expr expr) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof SimpleEvaluationContextBuilder and + m.hasName("build") and + ma = expr + ) +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll new file mode 100644 index 00000000000..dd6ebc43ee7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll @@ -0,0 +1,136 @@ +import java +import semmle.code.java.dataflow.DataFlow + +/** + * Methods that trigger evaluation of an expression. + */ +class ExpressionEvaluationMethod extends Method { + ExpressionEvaluationMethod() { + getDeclaringType() instanceof Expression and + ( + hasName("getValue") or + hasName("getValueTypeDescriptor") or + hasName("getValueType") or + hasName("setValue") + ) + } +} + +/** + * `WebRequest` interface is a source of tainted data. + */ +class WebRequestSource extends DataFlow::Node { + WebRequestSource() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof WebRequest and + ( + m.hasName("getHeader") or + m.hasName("getHeaderValues") or + m.hasName("getHeaderNames") or + m.hasName("getParameter") or + m.hasName("getParameterValues") or + m.hasName("getParameterNames") or + m.hasName("getParameterMap") + ) and + ma = asExpr() + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that converts `PropertyValues` + * to an array of `PropertyValue`, i.e. `tainted.getPropertyValues()`. + */ +predicate getPropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof PropertyValues and + m.hasName("getPropertyValues") + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that constructs `MutablePropertyValues`, + * i.e. `new MutablePropertyValues(tainted)`. + */ +predicate createMutablePropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof MutablePropertyValues | + node1.asExpr() = cc.getAnArgument() and + node2.asExpr() = cc + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that returns a name of `PropertyValue`, + * i.e. `tainted.getName()`. + */ +predicate getPropertyNameStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof PropertyValue and + m.hasName("getName") + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that converts `MutablePropertyValues` + * to a list of `PropertyValue`, i.e. `tainted.getPropertyValueList()`. + */ +predicate getPropertyValueListStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof MutablePropertyValues and + m.hasName("getPropertyValueList") + ) +} + +/** + * Holds if `node1` to `node2` is one of the dataflow steps that propagate + * tainted data via Spring properties. + */ +predicate springPropertiesStep(DataFlow::Node node1, DataFlow::Node node2) { + createMutablePropertyValuesStep(node1, node2) or + getPropertyNameStep(node1, node2) or + getPropertyValuesStep(node1, node2) or + getPropertyValueListStep(node1, node2) +} + +class PropertyValue extends RefType { + PropertyValue() { hasQualifiedName("org.springframework.beans", "PropertyValue") } +} + +class PropertyValues extends RefType { + PropertyValues() { hasQualifiedName("org.springframework.beans", "PropertyValues") } +} + +class MutablePropertyValues extends RefType { + MutablePropertyValues() { hasQualifiedName("org.springframework.beans", "MutablePropertyValues") } +} + +class SimpleEvaluationContext extends RefType { + SimpleEvaluationContext() { + hasQualifiedName("org.springframework.expression.spel.support", "SimpleEvaluationContext") + } +} + +class SimpleEvaluationContextBuilder extends RefType { + SimpleEvaluationContextBuilder() { + hasQualifiedName("org.springframework.expression.spel.support", + "SimpleEvaluationContext$Builder") + } +} + +class WebRequest extends RefType { + WebRequest() { hasQualifiedName("org.springframework.web.context.request", "WebRequest") } +} + +class Expression extends RefType { + Expression() { hasQualifiedName("org.springframework.expression", "Expression") } +} + +class ExpressionParser extends RefType { + ExpressionParser() { hasQualifiedName("org.springframework.expression", "ExpressionParser") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java new file mode 100644 index 00000000000..4942bee79f6 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java @@ -0,0 +1,8 @@ +public void evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String expression = reader.readLine(); + MVEL.eval(expression); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java new file mode 100644 index 00000000000..b16a1eb50d2 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java @@ -0,0 +1,10 @@ +public Object evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String string = reader.readLine(); + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(string); + return expression.getValue(); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java new file mode 100644 index 00000000000..65698ac33a3 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java @@ -0,0 +1,101 @@ +public static void main(String[] args) { + { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + try { //GOOD: verify the certificate + Certificate[] certs = session.getPeerCertificates(); + X509Certificate x509 = (X509Certificate) certs[0]; + check(new String[]{host}, x509); + return true; + } catch (SSLException e) { + return false; + } + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // BAD: accept even if the hostname doesn't match + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + { + X509TrustManager trustAllCertManager = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // BAD: trust any server cert + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; //BAD: doesn't check cert issuer + } + }; + } + + { + X509TrustManager trustCertManager = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + pkixTrustManager.checkServerTrusted(chain, authType); //GOOD: validate the server cert + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; //GOOD: Validate the cert issuer + } + }; + } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL engine to trigger hostname verification + sslEngine.setSSLParameters(sslParameters); + } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); //BAD: No endpointIdentificationAlgorithm set + } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + final SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL socket to trigger hostname verification + socket.setSSLParameters(sslParameters); + } + + { + com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory(); + connectionFactory.useSslProtocol(); + connectionFactory.enableHostnameVerification(); //GOOD: Enable hostname verification for rabbitmq ConnectionFactory + } + + { + com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory(); + connectionFactory.useSslProtocol(); //BAD: Hostname verification for rabbitmq ConnectionFactory is not enabled + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp new file mode 100644 index 00000000000..2e8d08fd68b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp @@ -0,0 +1,46 @@ + + + + +

    Java offers two mechanisms for SSL authentication - trust manager and hostname verifier. Trust manager validates the peer's certificate chain while hostname verification establishes that the hostname in the URL matches the hostname in the server's identification.

    +

    And when SSLSocket or SSLEngine is created without a valid parameter of setEndpointIdentificationAlgorithm, hostname verification is disabled by default.

    +

    Unsafe implementation of the interface X509TrustManager, HostnameVerifier, and SSLSocket/SSLEngine ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks.

    +

    This query checks whether trust manager is set to trust all certificates, the hostname verifier is turned off, or setEndpointIdentificationAlgorithm is missing. The query also covers a special implementation com.rabbitmq.client.ConnectionFactory.

    +
    + + +

    Validate SSL certificate in SSL authentication.

    +
    + + +

    The following two examples show two ways of configuring X509 trust cert manager and hostname verifier. In the 'BAD' case, +no validation is performed thus any certificate is trusted. In the 'GOOD' case, the proper validation is performed.

    + +
    + + +
  • +CWE-273 +
  • +
  • +How to fix apps containing an unsafe implementation of TrustManager +
  • +
  • +Testing Endpoint Identify Verification (MSTG-NETWORK-3) +
  • +
  • +CVE-2018-17187: Apache Qpid Proton-J transport issue with hostname verification +
  • +
  • +CVE-2018-8034: Apache Tomcat - host name verification when using TLS with the WebSocket client +
  • +
  • +CVE-2018-11087: Pivotal Spring AMQP vulnerability due to lack of hostname validation +
  • +
  • +CVE-2018-11775: TLS hostname verification issue when using the Apache ActiveMQ Client +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql new file mode 100644 index 00000000000..497e87b37ac --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -0,0 +1,246 @@ +/** + * @name Unsafe certificate trust and improper hostname verification + * @description Unsafe implementation of the interface X509TrustManager, HostnameVerifier, and SSLSocket/SSLEngine ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks. + * @kind problem + * @id java/unsafe-cert-trust + * @tags security + * external/cwe-273 + */ + +import java +import semmle.code.java.security.Encryption + +/** + * X509TrustManager class that blindly trusts all certificates in server SSL authentication + */ +class X509TrustAllManager extends RefType { + X509TrustAllManager() { + this.getASupertype*() instanceof X509TrustManager and + exists(Method m1 | + m1.getDeclaringType() = this and + m1.hasName("checkServerTrusted") and + m1.getBody().getNumStmt() = 0 + ) and + exists(Method m2, ReturnStmt rt2 | + m2.getDeclaringType() = this and + m2.hasName("getAcceptedIssuers") and + rt2.getEnclosingCallable() = m2 and + rt2.getResult() instanceof NullLiteral + ) + } +} + +/** + * The init method of SSLContext with the trust all manager, which is sslContext.init(..., serverTMs, ...) + */ +class X509TrustAllManagerInit extends MethodAccess { + X509TrustAllManagerInit() { + this.getMethod().hasName("init") and + this.getMethod().getDeclaringType() instanceof SSLContext and //init method of SSLContext + ( + exists(ArrayInit ai | + this.getArgument(1).(ArrayCreationExpr).getInit() = ai and + ai.getInit(0).(VarAccess).getVariable().getInitializer().getType().(Class).getASupertype*() + instanceof X509TrustAllManager //Scenario of context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); + ) + or + exists(Variable v, ArrayInit ai | + this.getArgument(1).(VarAccess).getVariable() = v and + ai.getParent() = v.getAnAssignedValue() and + ai.getInit(0).getType().(Class).getASupertype*() instanceof X509TrustAllManager //Scenario of context.init(null, serverTMs, null); + ) + ) + } +} + +/** + * HostnameVerifier class that allows a certificate whose CN (Common Name) does not match the host name in the URL + */ +class TrustAllHostnameVerifier extends RefType { + TrustAllHostnameVerifier() { + this.getASupertype*() instanceof HostnameVerifier and + exists(Method m, ReturnStmt rt | + m.getDeclaringType() = this and + m.hasName("verify") and + rt.getEnclosingCallable() = m and + rt.getResult().(BooleanLiteral).getBooleanValue() = true + ) + } +} + +/** + * The setDefaultHostnameVerifier method of HttpsURLConnection with the trust all configuration + */ +class TrustAllHostnameVerify extends MethodAccess { + TrustAllHostnameVerify() { + this.getMethod().hasName("setDefaultHostnameVerifier") and + this.getMethod().getDeclaringType() instanceof HttpsURLConnection and //httpsURLConnection.setDefaultHostnameVerifier method + ( + exists(NestedClass nc | + nc.getASupertype*() instanceof TrustAllHostnameVerifier and + this.getArgument(0).getType() = nc //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {...}); + ) + or + exists(Variable v | + this.getArgument(0).(VarAccess).getVariable() = v and + v.getInitializer().getType() instanceof TrustAllHostnameVerifier //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(verifier); + ) + ) + } +} + +class SSLEngine extends RefType { + SSLEngine() { this.hasQualifiedName("javax.net.ssl", "SSLEngine") } +} + +class Socket extends RefType { + Socket() { this.hasQualifiedName("java.net", "Socket") } +} + +class SocketFactory extends RefType { + SocketFactory() { this.hasQualifiedName("javax.net", "SocketFactory") } +} + +class SSLSocket extends RefType { + SSLSocket() { this.hasQualifiedName("javax.net.ssl", "SSLSocket") } +} + +/** + * has setEndpointIdentificationAlgorithm set correctly + */ +predicate setEndpointIdentificationAlgorithm(MethodAccess createSSL) { + exists( + Variable sslo, MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set + | + createSSL = sslo.getAnAssignedValue() and + ma.getQualifier() = sslo.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") and + ma.getArgument(0) = sslparams.getAnAccess() and + exists(MethodAccess setepa | + setepa.getQualifier() = sslparams.getAnAccess() and + setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and + not setepa.getArgument(0) instanceof NullLiteral + ) + ) +} + +/** + * has setEndpointIdentificationAlgorithm set correctly + */ +predicate hasEndpointIdentificationAlgorithm(Variable ssl) { + exists( + MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set + | + ma.getQualifier() = ssl.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") and + ma.getArgument(0) = sslparams.getAnAccess() and + exists(MethodAccess setepa | + setepa.getQualifier() = sslparams.getAnAccess() and + setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and + not setepa.getArgument(0) instanceof NullLiteral + ) + ) +} + +/** + * Cast of Socket to SSLSocket + */ +predicate sslCast(MethodAccess createSSL) { + exists(Variable ssl, CastExpr ce | + ce.getExpr() = createSSL and + ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and + ssl.getType() instanceof SSLSocket //With a type cast `SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443)` + ) +} + +/** + * SSL object is created in a separate method call or in the same method + */ +predicate hasFlowPath(MethodAccess createSSL, Variable ssl) { + ( + createSSL = ssl.getAnAssignedValue() + or + exists(CastExpr ce | + ce.getExpr() = createSSL and + ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl //With a type cast like SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + ) + ) + or + exists(MethodAccess tranm | + createSSL.getEnclosingCallable() = tranm.getMethod() and + tranm.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and + not setEndpointIdentificationAlgorithm(createSSL) //Check the scenario of invocation before used in the current method + ) +} + +/** + * Not have the SSLParameter set + */ +predicate hasNoEndpointIdentificationSet(MethodAccess createSSL, Variable ssl) { + //No setSSLParameters set + hasFlowPath(createSSL, ssl) and + not exists(MethodAccess ma | + ma.getQualifier() = ssl.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") + ) + or + //No endpointIdentificationAlgorithm set with setSSLParameters + hasFlowPath(createSSL, ssl) and + not setEndpointIdentificationAlgorithm(createSSL) +} + +/** + * The setEndpointIdentificationAlgorithm method of SSLParameters with the ssl engine or socket + */ +class SSLEndpointIdentificationNotSet extends MethodAccess { + SSLEndpointIdentificationNotSet() { + ( + this.getMethod().hasName("createSSLEngine") and + this.getMethod().getDeclaringType() instanceof SSLContext //createEngine method of SSLContext + or + this.getMethod().hasName("createSocket") and + this.getMethod().getDeclaringType() instanceof SocketFactory and + this.getMethod().getReturnType() instanceof Socket and + sslCast(this) //createSocket method of SocketFactory + ) and + exists(Variable ssl | + hasNoEndpointIdentificationSet(this, ssl) and //Not set in itself + not exists(VariableAssign ar, Variable newSsl | + ar.getSource() = this.getCaller().getAReference() and + ar.getDestVar() = newSsl and + hasEndpointIdentificationAlgorithm(newSsl) //Not set in its caller either + ) + ) and + not exists(MethodAccess ma | ma.getMethod() instanceof HostnameVerifierVerify) //Reduce false positives since this method access set default hostname verifier + } +} + +class RabbitMQConnectionFactory extends RefType { + RabbitMQConnectionFactory() { this.hasQualifiedName("com.rabbitmq.client", "ConnectionFactory") } +} + +/** + * The com.rabbitmq.client.ConnectionFactory useSslProtocol method access without enableHostnameVerification + */ +class RabbitMQEnableHostnameVerificationNotSet extends MethodAccess { + RabbitMQEnableHostnameVerificationNotSet() { + this.getMethod().hasName("useSslProtocol") and + this.getMethod().getDeclaringType() instanceof RabbitMQConnectionFactory and + exists(Variable v | + v.getType() instanceof RabbitMQConnectionFactory and + this.getQualifier() = v.getAnAccess() and + not exists(MethodAccess ma | + ma.getMethod().hasName("enableHostnameVerification") and + ma.getQualifier() = v.getAnAccess() + ) + ) + } +} + +from MethodAccess aa +where + aa instanceof TrustAllHostnameVerify or + aa instanceof X509TrustAllManagerInit or + aa instanceof SSLEndpointIdentificationNotSet or + aa instanceof RabbitMQEnableHostnameVerificationNotSet +select aa, "Unsafe configuration of trusted certificates" diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp new file mode 100644 index 00000000000..9fbec38a4c1 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp @@ -0,0 +1,30 @@ + + + + +

    JavaMail is commonly used in Java applications to send emails. There are popular third-party libraries like Apache Commons Email which are built on JavaMail and facilitate integration. Authenticated mail sessions require user credentials and mail sessions can require SSL/TLS authentication. It is a common security vulnerability that host-specific certificate data is not validated or is incorrectly validated. Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack.

    +

    This query checks whether SSL certificate is validated when username/password is sent in authenticator and when SSL is enabled.

    +

    The query has code for both plain JavaMail invocation and mailing through Apache SimpleMail to make it more comprehensive.

    +
    + + +

    Validate SSL certificate when sensitive information is sent in email communications.

    +
    + + +

    The following two examples show two ways of configuring secure emails through JavaMail or Apache SimpleMail. In the 'BAD' case, +credentials are sent in an SSL session without certificate validation. In the 'GOOD' case, the certificate is validated.

    + + +
    + + +
  • +CWE-297 +Add support for specifying an SSL configuration for SmtpAppender (CVE-2020-9488) +SMTP SSL connection should check server identity +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql new file mode 100644 index 00000000000..6b9176ce034 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql @@ -0,0 +1,103 @@ +/** + * @id java/insecure-smtp-ssl + * @name Insecure JavaMail SSL Configuration + * @description Java application configured to use authenticated mail session over SSL does not validate the SSL certificate to properly ensure that it is actually associated with that host. + * @kind problem + * @tags security + * external/cwe-297 + */ + +import java + +/** + * The method to set Java properties + */ +class SetPropertyMethod extends Method { + SetPropertyMethod() { + this.hasName("setProperty") and + this.getDeclaringType().hasQualifiedName("java.util", "Properties") + or + this.hasName("put") and + this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.util", "Dictionary") + } +} + +/** + * The insecure way to set Java properties in mail sessions. + * 1. Set the mail.smtp.auth property to provide the SMTP Transport with a username and password when connecting to the SMTP server or + * set the mail.smtp.ssl.socketFactory/mail.smtp.ssl.socketFactory.class property to create an SMTP SSL socket. + * 2. No mail.smtp.ssl.checkserveridentity property is enabled. + */ +predicate isInsecureMailPropertyConfig(VarAccess propertiesVarAccess) { + exists(MethodAccess ma | + ma.getMethod() instanceof SetPropertyMethod and + ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and + ( + getStringValue(ma.getArgument(0)).matches("%.auth%") and //mail.smtp.auth + getStringValue(ma.getArgument(1)) = "true" + or + getStringValue(ma.getArgument(0)).matches("%.socketFactory%") //mail.smtp.socketFactory or mail.smtp.socketFactory.class + ) + ) and + not exists(MethodAccess ma | + ma.getMethod() instanceof SetPropertyMethod and + ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and + ( + getStringValue(ma.getArgument(0)).matches("%.ssl.checkserveridentity%") and //mail.smtp.ssl.checkserveridentity + getStringValue(ma.getArgument(1)) = "true" + ) + ) +} + +/** + * Helper method to get string value of an argument + */ +string getStringValue(Expr expr) { + result = expr.(CompileTimeConstantExpr).getStringValue() + or + result = getStringValue(expr.(AddExpr).getLeftOperand()) + or + result = getStringValue(expr.(AddExpr).getRightOperand()) +} + +/** + * The JavaMail session class `javax.mail.Session` + */ +class MailSession extends RefType { + MailSession() { this.hasQualifiedName("javax.mail", "Session") } +} + +/** + * The class of Apache SimpleMail + */ +class SimpleMail extends RefType { + SimpleMail() { this.hasQualifiedName("org.apache.commons.mail", "SimpleEmail") } +} + +/** + * Has TLS/SSL enabled with SimpleMail + */ +predicate enableTLSWithSimpleMail(MethodAccess ma) { + ma.getMethod().hasName("setSSLOnConnect") and + ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true +} + +/** + * Has no certificate check + */ +predicate hasNoCertCheckWithSimpleMail(VarAccess va) { + not exists(MethodAccess ma | + ma.getQualifier() = va.getVariable().getAnAccess() and + ma.getMethod().hasName("setSSLCheckServerIdentity") and + ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true + ) +} + +from MethodAccess ma +where + ma.getMethod().getDeclaringType() instanceof MailSession and + ma.getMethod().getName() = "getInstance" and + isInsecureMailPropertyConfig(ma.getArgument(0)) + or + enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier()) +select ma, "Java mailing has insecure SSL configuration" diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java b/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java new file mode 100644 index 00000000000..c5c41c0f698 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java @@ -0,0 +1,43 @@ +import java.util.Properties; + +import javax.activation.DataSource; +import javax.mail.Authenticator; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; + +import org.apache.logging.log4j.util.PropertiesUtil; + +class JavaMail { + public static void main(String[] args) { + // BAD: Don't have server certificate check + { + final Properties properties = PropertiesUtil.getSystemProperties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final Authenticator authenticator = buildAuthenticator("username", "password"); + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + + // GOOD: Have server certificate check + { + final Properties properties = PropertiesUtil.getSystemProperties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final Authenticator authenticator = buildAuthenticator("username", "password"); + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + properties.put("mail.smtp.ssl.checkserveridentity", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java b/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java new file mode 100644 index 00000000000..de7b022eb9b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java @@ -0,0 +1,40 @@ +import org.apache.commons.mail.DefaultAuthenticator; +import org.apache.commons.mail.Email; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; + +class SimpleMail { + public static void main(String[] args) throws EmailException { + // BAD: Don't have setSSLCheckServerIdentity set or set as false + { + Email email = new SimpleEmail(); + email.setHostName("hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("username", "password")); + email.setSSLOnConnect(true); + + //email.setSSLCheckServerIdentity(false); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } + + // GOOD: Have setSSLCheckServerIdentity set to true + { + Email email = new SimpleEmail(); + email.setHostName("hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("username", "password")); + email.setSSLOnConnect(true); + + email.setSSLCheckServerIdentity(true); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java new file mode 100644 index 00000000000..57b076f6a36 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java @@ -0,0 +1,10 @@ +public void validate(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + checker.setOcspResponder(OCSP_RESPONDER_URL); + checker.setOcspResponderCert(OCSP_RESPONDER_CERT); + params.addCertPathChecker(checker); + validator.validate(certPath, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java new file mode 100644 index 00000000000..82bb697ce4a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java @@ -0,0 +1,5 @@ +public void validate(KeyStore cacerts, CertPath chain) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + validator.validate(chain, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp new file mode 100644 index 00000000000..c76b56b531a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp @@ -0,0 +1,63 @@ + + + + +

    Validating a certificate chain includes multiple steps. One of them is checking whether or not +certificates in the chain have been revoked. A certificate may be revoked due to multiple reasons. +One of the reasons why the certificate authority (CA) may revoke a certificate is that its private key +has been compromised. For example, the private key might have been stolen by an adversary. +In this case, the adversary may be able to impersonate the owner of the private key. +Therefore, trusting a revoked certificate may be dangerous.

    + +

    The Java Certification Path API provides a revocation checking mechanism +that supports both CRL and OCSP. +Revocation checking happens while building and validating certificate chains. +If at least one of the certificates is revoked, then an exception is thrown. +This mechanism is enabled by default. However, it may be disabled +by passing false to the PKIXParameters.setRevocationEnabled() method. +If an application doesn't set a custom PKIXRevocationChecker +via PKIXParameters.addCertPathChecker() +or PKIXParameters.setCertPathCheckers() methods, +then revocation checking is not going to happen.

    + +
    + + +

    An application should not disable the default revocationg checking mechanism +unless it provides a custom revocation checker.

    + +
    + + +

    The following example turns off revocation checking for validating a certificate chain. +That should be avoided.

    + + + +

    The next example uses the default revocation checking mechanism.

    + + + +

    The third example turns off the default revocation mechanism. However, it registers another +revocation checker that uses OCSP to obtain revocation status of certificates.

    + + + +
    + + +
  • + Wikipedia: + Public key certificate +
  • +
  • + Java SE Documentation: + Java PKI Programmer's Guide +
  • +
  • + Java SE API Specification: + CertPathValidator +
  • + +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql new file mode 100644 index 00000000000..c38cc39b126 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql @@ -0,0 +1,20 @@ +/** + * @name Disabled ceritificate revocation checking + * @description Using revoked certificates is dangerous. + * Therefore, revocation status of certificates in a chain should be checked. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/disabled-certificate-revocation-checking + * @tags security + * external/cwe/cwe-299 + */ + +import java +import RevocationCheckingLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, DisabledRevocationCheckingConfig config +where config.hasFlowPath(source, sink) +select source.getNode(), source, sink, "Revocation checking is disabled $@.", source.getNode(), + "here" diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java new file mode 100644 index 00000000000..24aec8da1e7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java @@ -0,0 +1,6 @@ +public void validateUnsafe(KeyStore cacerts, CertPath chain) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + validator.validate(chain, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll new file mode 100644 index 00000000000..39642de21fd --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll @@ -0,0 +1,60 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow + +/** + * A taint-tracking configuration for disabling revocation checking. + */ +class DisabledRevocationCheckingConfig extends TaintTracking::Configuration { + DisabledRevocationCheckingConfig() { this = "DisabledRevocationCheckingConfig" } + + override predicate isSource(DataFlow::Node source) { + exists(BooleanLiteral b | b.getBooleanValue() = false | source.asExpr() = b) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SetRevocationEnabledSink } +} + +/** + * A sink that disables revocation checking, + * i.e. calling `PKIXParameters.setRevocationEnabled(false)` + * without setting a custom revocation checker in `PKIXParameters`. + */ +class SetRevocationEnabledSink extends DataFlow::ExprNode { + SetRevocationEnabledSink() { + exists(MethodAccess setRevocationEnabledCall | + setRevocationEnabledCall.getMethod() instanceof SetRevocationEnabledMethod and + setRevocationEnabledCall.getArgument(0) = getExpr() and + not exists(MethodAccess ma, Method m | m = ma.getMethod() | + (m instanceof AddCertPathCheckerMethod or m instanceof SetCertPathCheckersMethod) and + ma.getQualifier().(VarAccess).getVariable() = + setRevocationEnabledCall.getQualifier().(VarAccess).getVariable() + ) + ) + } +} + +class SetRevocationEnabledMethod extends Method { + SetRevocationEnabledMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("setRevocationEnabled") + } +} + +class AddCertPathCheckerMethod extends Method { + AddCertPathCheckerMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("addCertPathChecker") + } +} + +class SetCertPathCheckersMethod extends Method { + SetCertPathCheckersMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("setCertPathCheckers") + } +} + +class PKIXParameters extends RefType { + PKIXParameters() { hasQualifiedName("java.security.cert", "PKIXParameters") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java b/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java new file mode 100644 index 00000000000..7204908662e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java @@ -0,0 +1,6 @@ +public SSLSocket connect(String host, int port) + throws NoSuchAlgorithmException, IOException { + + SSLContext context = SSLContext.getInstance("TLSv1.3"); + return (SSLSocket) context.getSocketFactory().createSocket(host, port); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll new file mode 100644 index 00000000000..bfa2530b07e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll @@ -0,0 +1,111 @@ +import java +import semmle.code.java.security.Encryption +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + +/** + * A taint-tracking configuration for unsafe SSL and TLS versions. + */ +class UnsafeTlsVersionConfig extends TaintTracking::Configuration { + UnsafeTlsVersionConfig() { this = "UnsafeTlsVersion::UnsafeTlsVersionConfig" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof UnsafeTlsVersion } + + override predicate isSink(DataFlow::Node sink) { + sink instanceof SslContextGetInstanceSink or + sink instanceof CreateSslParametersSink or + sink instanceof SslParametersSetProtocolsSink or + sink instanceof SetEnabledProtocolsSink + } +} + +/** + * A sink that sets protocol versions in `SSLContext`, + * i.e `SSLContext.getInstance(protocol)`. + */ +class SslContextGetInstanceSink extends DataFlow::ExprNode { + SslContextGetInstanceSink() { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof SSLContext and + m.hasName("getInstance") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * A sink that creates `SSLParameters` with specified protocols, + * i.e. `new SSLParameters(ciphersuites, protocols)`. + */ +class CreateSslParametersSink extends DataFlow::ExprNode { + CreateSslParametersSink() { + exists(ConstructorCall cc | cc.getConstructedType() instanceof SSLParameters | + cc.getArgument(1) = asExpr() + ) + } +} + +/** + * A sink that sets protocol versions for `SSLParameters`, + * i.e. `parameters.setProtocols(versions)`. + */ +class SslParametersSetProtocolsSink extends DataFlow::ExprNode { + SslParametersSetProtocolsSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof SSLParameters and + m.hasName("setProtocols") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * A sink that sets protocol versions for `SSLSocket`, `SSLServerSocket`, and `SSLEngine`, + * i.e. `socket.setEnabledProtocols(versions)` or `engine.setEnabledProtocols(versions)`. + */ +class SetEnabledProtocolsSink extends DataFlow::ExprNode { + SetEnabledProtocolsSink() { + exists(MethodAccess ma, Method m, RefType type | + m = ma.getMethod() and type = m.getDeclaringType() + | + ( + type instanceof SSLSocket or + type instanceof SSLServerSocket or + type instanceof SSLEngine + ) and + m.hasName("setEnabledProtocols") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * Insecure SSL and TLS versions supported by JSSE. + */ +class UnsafeTlsVersion extends StringLiteral { + UnsafeTlsVersion() { + getValue() = "SSL" or + getValue() = "SSLv2" or + getValue() = "SSLv3" or + getValue() = "TLS" or + getValue() = "TLSv1" or + getValue() = "TLSv1.1" + } +} + +class SSLParameters extends RefType { + SSLParameters() { hasQualifiedName("javax.net.ssl", "SSLParameters") } +} + +class SSLSocket extends RefType { + SSLSocket() { hasQualifiedName("javax.net.ssl", "SSLSocket") } +} + +class SSLServerSocket extends RefType { + SSLServerSocket() { hasQualifiedName("javax.net.ssl", "SSLServerSocket") } +} + +class SSLEngine extends RefType { + SSLEngine() { hasQualifiedName("javax.net.ssl", "SSLEngine") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java new file mode 100644 index 00000000000..c2beff544c4 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java @@ -0,0 +1,6 @@ +public SSLSocket connect(String host, int port) + throws NoSuchAlgorithmException, IOException { + + SSLContext context = SSLContext.getInstance("SSLv3"); + return (SSLSocket) context.getSocketFactory().createSocket(host, port); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp new file mode 100644 index 00000000000..0ac8f621ede --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp @@ -0,0 +1,60 @@ + + + + +

    Transport Layer Security (TLS) provides a number of security features such as +confidentiality, integrity, replay prevention and authenticatin. +There are several versions of TLS protocols. The latest is TLS 1.3. +Unfortunately, older versions were found to be vulnerable to a number of attacks.

    + +
    + + +

    An application should use TLS 1.3. Currenlty, TLS 1.2 is also considered acceptable.

    + +
    + + +

    The following example shows how a socket with an unsafe TLS version may be created:

    + + + +

    The next example creates a socket with the latest TLS version:

    + + + +
    + + +
  • + Wikipedia: + Transport Layer Security +
  • + +
  • + OWASP: + Transport Layer Protection Cheat Sheet +
  • + +
  • + Java SE Documentation: + Java Secure Socket Extension (JSSE) Reference Guide +
  • + +
  • + Java SE API Specification: + SSLContext +
  • + +
  • + Java SE API Specification: + SSLParameters +
  • + +
  • + Java SE API Specification: + SSLSocket +
  • + +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql new file mode 100644 index 00000000000..38d7144049d --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql @@ -0,0 +1,20 @@ +/** + * @name Unsafe TLS version + * @description SSL and older TLS versions are known to be vulnerable. + * TLS 1.3 or at least TLS 1.2 should be used. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/unsafe-tls-version + * @tags security + * external/cwe/cwe-327 + */ + +import java +import SslLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeTlsVersionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ is unsafe", source.getNode(), + source.getNode().asExpr().(StringLiteral).getValue() diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp new file mode 100644 index 00000000000..cf6275239f7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp @@ -0,0 +1,25 @@ + + + + +

    Enabling directory listing in J2EE application servers introduces the vulnerability of filename and path disclosure, which could allow an attacker to read arbitrary files in the server web directory. This includes application source code and data, as well as credentials for back-end systems.

    +

    The query detects insecure configuration by validating its web configuration.

    +
    + + +

    Always disabling directory listing in the production environment.

    +
    + + +

    The following two examples show two ways of directory listing configuration. In the 'BAD' case, it is enabled. In the 'GOOD' case, it is disabled.

    + +
    + + +
  • + CWE-548: Exposure of Information Through Directory Listing + Directory listing + Directory traversal +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql new file mode 100644 index 00000000000..08a456137d0 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -0,0 +1,42 @@ +/** + * @name Directories and files exposure + * @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory, which could yield files containing sensitive information like source code and credentials to the attacker. + * @kind problem + * @id java/server-directory-listing + * @tags security + * external/cwe-548 + */ + +import java +import semmle.code.xml.WebXML + +/** + * The default `` element in a `web.xml` file. + */ +private class DefaultTomcatServlet extends WebServletClass { + DefaultTomcatServlet() { + this.getTextValue() = "org.apache.catalina.servlets.DefaultServlet" //Default servlet of Tomcat and other servlet containers derived from Tomcat like Glassfish + } +} + +/** + * The `` element in a `web.xml` file, nested under a `` element controlling directory listing. + */ +class DirectoryListingInitParam extends WebXMLElement { + DirectoryListingInitParam() { + getName() = "init-param" and + getAChild("param-name").getTextValue() = "listings" and + exists(WebServlet servlet | + getParent() = servlet and servlet.getAChild("servlet-class") instanceof DefaultTomcatServlet + ) + } + + /** + * Check the `` element (true - enabled, false - disabled) + */ + predicate isListingEnabled() { getAChild("param-value").getTextValue().toLowerCase() = "true" } +} + +from DirectoryListingInitParam initp +where initp.isListingEnabled() +select initp, "Directory listing should be disabled to mitigate filename and path disclosure" diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/web.xml b/java/ql/src/experimental/Security/CWE/CWE-548/web.xml new file mode 100644 index 00000000000..8b3b2bf4d40 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/web.xml @@ -0,0 +1,30 @@ + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + listings + + false + + 1 + + + + default + org.apache.catalina.servlets.DefaultServlet + + listings + + true + + 1 + + \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java new file mode 100644 index 00000000000..cc99ff46517 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java @@ -0,0 +1,17 @@ +import ognl.Ognl; +import ognl.OgnlException; + +public void evaluate(HttpServletRequest request, Object root) throws OgnlException { + String expression = request.getParameter("expression"); + + // BAD: User provided expression is evaluated + Ognl.getValue(expression, root); + + // GOOD: The name is validated and expression is evaluated in sandbox + System.setProperty("ognl.security.manager", ""); // Or add -Dognl.security.manager to JVM args + if (isValid(expression)) { + Ognl.getValue(expression, root); + } else { + // Reject the request + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp new file mode 100644 index 00000000000..e20d54f1d84 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp @@ -0,0 +1,33 @@ + + + +

    Object-Graph Navigation Language (OGNL) is an open-source Expression Language (EL) for Java. Due +to its ability to create or change executable code, OGNL is capable of introducing critical +security flaws to any application that uses it. Evaluation of unvalidated expressions can let +attacker to modify Java objects' properties or execute arbitrary code.

    +
    + + +

    The general recommendation is to not evaluate untrusted ONGL expressions. If user provided OGNL +expressions must be evaluated, do this in sandbox (add `-Dognl.security.manager` to JVM arguments) +and validate the expressions before evaluation.

    +
    + + +

    In the following examples, the code accepts an OGNL expression from the user and evaluates it. +

    + +

    In the first example, the user provided OGNL expression is parsed and evaluated.

    + +

    The second example validates the expression and evaluates it inside the sandbox.

    + + +
    + + +
  • OGNL library.
  • +
  • Struts security: Proactively protect from OGNL Expression Injections attacks.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql new file mode 100644 index 00000000000..e8a75591b98 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql @@ -0,0 +1,22 @@ +/** + * @name OGNL Expression Language statement with user-controlled input + * @description Evaluation of OGNL Expression Language statement with user-controlled input can + * lead to execution of arbitrary code. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/ognl-injection + * @tags security + * external/cwe/cwe-917 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import DataFlow::PathGraph +import OgnlInjectionLib + +from DataFlow::PathNode source, DataFlow::PathNode sink, OgnlInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "OGNL expression might include input from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll new file mode 100644 index 00000000000..569e18a29c3 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll @@ -0,0 +1,109 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import DataFlow::PathGraph + +/** + * A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation. + */ +class OgnlInjectionFlowConfig extends TaintTracking::Configuration { + OgnlInjectionFlowConfig() { this = "OgnlInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + parseCompileExpressionStep(node1, node2) + } +} + +/** The class `org.apache.commons.ognl.Ognl` or `ognl.Ognl`. */ +class TypeOgnl extends Class { + TypeOgnl() { + this.hasQualifiedName("org.apache.commons.ognl", "Ognl") or + this.hasQualifiedName("ognl", "Ognl") + } +} + +/** The interface `org.apache.commons.ognl.Node` or `ognl.Node`. */ +class TypeNode extends Interface { + TypeNode() { + this.hasQualifiedName("org.apache.commons.ognl", "Node") or + this.hasQualifiedName("ognl", "Node") + } +} + +/** The class `com.opensymphony.xwork2.ognl.OgnlUtil`. */ +class TypeOgnlUtil extends Class { + TypeOgnlUtil() { this.hasQualifiedName("com.opensymphony.xwork2.ognl", "OgnlUtil") } +} + +/** + * OGNL sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue` or `setValue` + * method from `Ognl` or `getValue` or `setValue` method from `Node`. + */ +predicate ognlSinkMethod(Method m, int index) { + ( + m.getDeclaringType() instanceof TypeOgnl + or + m.getDeclaringType().getAnAncestor*() instanceof TypeNode + ) and + ( + m.hasName("getValue") or + m.hasName("setValue") + ) and + index = 0 +} + +/** + * Struts sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue`, `setValue` or + * `callMethod` method from `OgnlUtil`. + */ +predicate strutsSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeOgnlUtil and + ( + m.hasName("getValue") or + m.hasName("setValue") or + m.hasName("callMethod") + ) and + index = 0 +} + +/** Holds if parameter at index `index` in method `m` is OGNL injection sink. */ +predicate ognlInjectionSinkMethod(Method m, int index) { + ognlSinkMethod(m, index) or + strutsSinkMethod(m, index) +} + +/** A data flow sink for unvalidated user input that is used in OGNL EL evaluation. */ +class OgnlInjectionSink extends DataFlow::ExprNode { + OgnlInjectionSink() { + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + (ma.getArgument(index) = this.getExpr() or ma.getQualifier() = this.getExpr()) and + ognlInjectionSinkMethod(m, index) + ) + } +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `Object` or `Node`, + * i.e. `Ognl.parseExpression(tainted)` or `Ognl.compileExpression(tainted)`. + */ +predicate parseCompileExpressionStep(ExprNode n1, ExprNode n2) { + exists(MethodAccess ma, Method m, int index | + n1.asExpr() = ma.getArgument(index) and + n2.asExpr() = ma and + ma.getMethod() = m and + m.getDeclaringType() instanceof TypeOgnl + | + m.hasName("parseExpression") and index = 0 + or + m.hasName("compileExpression") and index = 2 + ) +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll new file mode 100644 index 00000000000..73b5e1a4f9f --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll @@ -0,0 +1,16 @@ +import java + +/** The class `javax.naming.InitialContext`. */ +class TypeInitialContext extends Class { + TypeInitialContext() { this.hasQualifiedName("javax.naming", "InitialContext") } +} + +/** The class `javax.naming.CompositeName`. */ +class TypeCompositeName extends Class { + TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") } +} + +/** The class `javax.naming.CompoundName`. */ +class TypeCompoundName extends Class { + TypeCompoundName() { this.hasQualifiedName("javax.naming", "CompoundName") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll new file mode 100644 index 00000000000..55e42f14fcf --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.apache.shiro.jndi.JndiTemplate`. */ +class TypeShiroJndiTemplate extends Class { + TypeShiroJndiTemplate() { this.hasQualifiedName("org.apache.shiro.jndi", "JndiTemplate") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll new file mode 100644 index 00000000000..6033e359b17 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.springframework.jndi.JndiTemplate`. */ +class TypeSpringJndiTemplate extends Class { + TypeSpringJndiTemplate() { this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") } +} diff --git a/java/ql/src/external/Clover.qll b/java/ql/src/external/Clover.qll index fdc0584d672..d17acfd8408 100644 --- a/java/ql/src/external/Clover.qll +++ b/java/ql/src/external/Clover.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Clover reports. */ + import java /** @@ -18,6 +20,7 @@ class CloverCoverage extends XMLElement { this.getName() = "coverage" } + /** Gets a project for this `coverage` element. */ CloverProject getAProject() { result = this.getAChild() } } @@ -27,6 +30,7 @@ class CloverCoverage extends XMLElement { * all subclasses of this class, to share code. */ abstract class CloverMetricsContainer extends XMLElement { + /** Gets the Clover `metrics` child element for this element. */ CloverMetrics getMetrics() { result = this.getAChild() } } @@ -44,42 +48,61 @@ class CloverMetrics extends XMLElement { private float ratio(string name) { result = attr("covered" + name) / attr(name).(float) } + /** Gets the value of the `conditionals` attribute. */ int getNumConditionals() { result = attr("conditionals") } + /** Gets the value of the `coveredconditionals` attribute. */ int getNumCoveredConditionals() { result = attr("coveredconditionals") } + /** Gets the value of the `statements` attribute. */ int getNumStatements() { result = attr("statements") } + /** Gets the value of the `coveredstatements` attribute. */ int getNumCoveredStatements() { result = attr("coveredstatements") } + /** Gets the value of the `elements` attribute. */ int getNumElements() { result = attr("elements") } + /** Gets the value of the `coveredelements` attribute. */ int getNumCoveredElements() { result = attr("coveredelements") } + /** Gets the value of the `methods` attribute. */ int getNumMethods() { result = attr("methods") } + /** Gets the value of the `coveredmethods` attribute. */ int getNumCoveredMethods() { result = attr("coveredmethods") } + /** Gets the value of the `loc` attribute. */ int getNumLoC() { result = attr("loc") } + /** Gets the value of the `ncloc` attribute. */ int getNumNonCommentedLoC() { result = attr("ncloc") } + /** Gets the value of the `packages` attribute. */ int getNumPackages() { result = attr("packages") } + /** Gets the value of the `files` attribute. */ int getNumFiles() { result = attr("files") } + /** Gets the value of the `classes` attribute. */ int getNumClasses() { result = attr("classes") } + /** Gets the value of the `complexity` attribute. */ int getCloverComplexity() { result = attr("complexity") } + /** Gets the ratio of the `coveredconditionals` attribute over the `conditionals` attribute. */ float getConditionalCoverage() { result = ratio("conditionals") } + /** Gets the ratio of the `coveredstatements` attribute over the `statements` attribute. */ float getStatementCoverage() { result = ratio("statements") } + /** Gets the ratio of the `coveredelements` attribute over the `elements` attribute. */ float getElementCoverage() { result = ratio("elements") } + /** Gets the ratio of the `coveredmethods` attribute over the `methods` attribute. */ float getMethodCoverage() { result = ratio("methods") } + /** Gets the ratio of the `ncloc` attribute over the `loc` attribute. */ float getNonCommentedLoCRatio() { result = attr("ncloc") / attr("loc") } } @@ -100,6 +123,7 @@ class CloverPackage extends CloverMetricsContainer { this.getName() = "package" } + /** Gets the Java package for this Clover package. */ Package getRealPackage() { result.hasName(getAttribute("name").getValue()) } } @@ -122,8 +146,10 @@ class CloverClass extends CloverMetricsContainer { this.getName() = "class" } + /** Gets the Clover package for this Clover class. */ CloverPackage getPackage() { result = getParent().(CloverFile).getParent() } + /** Gets the Java type for this Clover class. */ RefType getRealClass() { result .hasQualifiedName(getPackage().getAttribute("name").getValue(), diff --git a/java/ql/src/localDefinitions.ql b/java/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..883762b6a06 --- /dev/null +++ b/java/ql/src/localDefinitions.ql @@ -0,0 +1,16 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id java/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Element e, Element def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/java/ql/src/localReferences.ql b/java/ql/src/localReferences.ql new file mode 100644 index 00000000000..51d1f6eb412 --- /dev/null +++ b/java/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id java/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Element e, Element def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/java/ql/src/meta/ssa/AmbiguousToString.ql b/java/ql/src/meta/ssa/AmbiguousToString.ql index 7dacb7ac8a3..ef9439705de 100644 --- a/java/ql/src/meta/ssa/AmbiguousToString.ql +++ b/java/ql/src/meta/ssa/AmbiguousToString.ql @@ -4,8 +4,8 @@ * sub-classes of 'SsaVariable'. * @kind problem * @problem.severity error - * @id java/sanity/non-unique-ssa-tostring - * @tags sanity + * @id java/consistency/non-unique-ssa-tostring + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/TooFewPhiInputs.ql b/java/ql/src/meta/ssa/TooFewPhiInputs.ql index 3c868610c1d..3bf75a91856 100644 --- a/java/ql/src/meta/ssa/TooFewPhiInputs.ql +++ b/java/ql/src/meta/ssa/TooFewPhiInputs.ql @@ -3,8 +3,8 @@ * @description A phi node should have at least two inputs. * @kind problem * @problem.severity error - * @id java/sanity/too-few-phi-inputs - * @tags sanity + * @id java/consistency/too-few-phi-inputs + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql b/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql index 172f620912b..1979c218ac2 100644 --- a/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql +++ b/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql @@ -4,8 +4,8 @@ * and should therefore have a prior definition. * @kind problem * @problem.severity error - * @id java/sanity/uncertain-ssa-update-without-prior-def - * @tags sanity + * @id java/consistency/uncertain-ssa-update-without-prior-def + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql b/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql index 421252fd508..fc776067782 100644 --- a/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql +++ b/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql @@ -4,8 +4,8 @@ * should have a unique associated SSA variable. * @kind problem * @problem.severity error - * @id java/sanity/use-without-unique-ssa-variable - * @tags sanity + * @id java/consistency/use-without-unique-ssa-variable + * @tags consistency */ import java diff --git a/java/ql/src/semmle/code/FileSystem.qll b/java/ql/src/semmle/code/FileSystem.qll index c2b39223a54..28015d3ba4d 100755 --- a/java/ql/src/semmle/code/FileSystem.qll +++ b/java/ql/src/semmle/code/FileSystem.qll @@ -151,33 +151,6 @@ class Container extends @container, Top { * This is the absolute path of the container. */ override string toString() { result = getAbsolutePath() } - - /** - * DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead. - * - * Gets the name of this container. - */ - deprecated string getName() { result = getAbsolutePath() } - - /** - * DEPRECATED: use `getBaseName()` or `getStem()` instead. - * - * The short name of this container, excluding its path and (for files) extension. - * - * For folders, the short name includes the extension (if any), so the short name - * of the folder with absolute path `/home/user/.m2` is `.m2`. - */ - deprecated string getShortName() { - folders(this, _, result) or - files(this, _, result, _, _) - } - - /** - * DEPRECATED: use `getAbsolutePath()` instead. - * - * Gets the full name of this container, including its path and extension (if any). - */ - deprecated string getFullName() { result = getAbsolutePath() } } /** A folder. */ @@ -198,13 +171,6 @@ class File extends Container, @file { /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - - /** - * DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead. - * - * Holds if this file has the specified `name`. - */ - deprecated predicate hasName(string name) { name = this.getAbsolutePath() } } /** diff --git a/java/ql/src/semmle/code/Location.qll b/java/ql/src/semmle/code/Location.qll index a34bba9ddc7..5cb97a39979 100755 --- a/java/ql/src/semmle/code/Location.qll +++ b/java/ql/src/semmle/code/Location.qll @@ -90,16 +90,16 @@ class Top extends @top { /** A location maps language elements to positions in source files. */ class Location extends @location { - /** Gets the line number where this location starts. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { locations_default(this, _, result, _, _, _) } - /** Gets the column number where this location starts. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { locations_default(this, _, _, result, _, _) } - /** Gets the line number where this location ends. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { locations_default(this, _, _, _, result, _) } - /** Gets the column number where this location ends. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { locations_default(this, _, _, _, _, result) } /** diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index 820f49487b7..f482398a74f 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -405,7 +405,7 @@ private module ControlFlowGraphImpl { * Expressions and statements with CFG edges in post-order AST traversal. * * This includes most expressions, except those that initiate or propagate branching control - * flow (`LogicExpr`, `ConditionalExpr`), and parentheses, which aren't in the CFG. + * flow (`LogicExpr`, `ConditionalExpr`). * Only a few statements are included; those with specific side-effects * occurring after the evaluation of their children, that is, `Call`, `ReturnStmt`, * and `ThrowStmt`. CFG nodes without child nodes in the CFG that may complete @@ -429,9 +429,10 @@ private module ControlFlowGraphImpl { or this instanceof CastExpr or - this instanceof InstanceOfExpr + this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern() or - this instanceof LocalVariableDeclExpr + this instanceof LocalVariableDeclExpr and + not this = any(InstanceOfExpr ioe).getLocalVariableDeclExpr() or this instanceof RValue or @@ -573,12 +574,16 @@ private module ControlFlowGraphImpl { or result = first(n.(PostOrderNode).firstChild()) or + result = first(n.(InstanceOfExpr).getExpr()) + or result = first(n.(SynchronizedStmt).getExpr()) or result = n and n instanceof Stmt and not n instanceof PostOrderNode and not n instanceof SynchronizedStmt + or + result = n and n instanceof SwitchExpr } /** @@ -705,6 +710,12 @@ private module ControlFlowGraphImpl { last(condexpr.getTrueExpr(), last, completion) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | + last = n and completion = basicBooleanCompletion(false) + or + last = ioe.getLocalVariableDeclExpr() and completion = basicBooleanCompletion(true) + ) + or // The last node of a node executed in post-order is the node itself. n.(PostOrderNode).mayCompleteNormally() and last = n and completion = NormalCompletion() or @@ -914,6 +925,14 @@ private module ControlFlowGraphImpl { result = first(e.getFalseExpr()) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() | + last(ioe.getExpr(), n, completion) and completion = NormalCompletion() and result = ioe + or + n = ioe and + result = ioe.getLocalVariableDeclExpr() and + completion = basicBooleanCompletion(true) + ) + or // In other expressions control flows from left to right and ends in the node itself. exists(PostOrderNode p, int i | last(p.getChildNode(i), n, completion) and completion = NormalCompletion() diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index dba1baf6148..63fc61bf1aa 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -60,6 +60,12 @@ class Expr extends ExprParent, @expr { /** Gets the statement containing this expression, if any. */ Stmt getEnclosingStmt() { statementEnclosingExpr(this, result) } + /** + * Gets a statement that directly or transitively contains this expression, if any. + * This is equivalent to `this.getEnclosingStmt().getEnclosingStmt*()`. + */ + Stmt getAnEnclosingStmt() { result = this.getEnclosingStmt().getEnclosingStmt*() } + /** Gets a child of this expression. */ Expr getAChildExpr() { exprs(result, _, _, this, _) } @@ -305,10 +311,6 @@ class CompileTimeConstantExpr extends Expr { /** * Gets the integer value of this expression, where possible. * - * All computations are performed on QL 32-bit `int`s, so no - * truncation is performed in the case of overflow within `byte` or `short`: - * `((byte)127)+((byte)1)` evaluates to 128 rather than to -128. - * * Note that this does not handle the following cases: * * - values of type `long`, @@ -332,7 +334,10 @@ class CompileTimeConstantExpr extends Expr { else if cast.getType().hasName("short") then result = (val + 32768).bitAnd(65535) - 32768 - else result = val + else + if cast.getType().hasName("char") + then result = val.bitAnd(65535) + else result = val ) or result = this.(PlusExpr).getExpr().(CompileTimeConstantExpr).getIntValue() @@ -413,7 +418,7 @@ class ArrayAccess extends Expr, @arrayaccess { /** * An array creation expression. * - * For example, an expression such as `new String[3][2]` or + * For example, an expression such as `new String[2][3]` or * `new String[][] { { "a", "b", "c" } , { "d", "e", "f" } }`. * * In both examples, `String` is the type name. In the first @@ -1051,6 +1056,18 @@ class MemberRefExpr extends FunctionalExpr, @memberref { override string toString() { result = "...::..." } } +/** A conditional expression or a `switch` expression. */ +class ChooseExpr extends Expr { + ChooseExpr() { this instanceof ConditionalExpr or this instanceof SwitchExpr } + + /** Gets a result expression of this `switch` or conditional expression. */ + Expr getAResultExpr() { + result = this.(ConditionalExpr).getTrueExpr() or + result = this.(ConditionalExpr).getFalseExpr() or + result = this.(SwitchExpr).getAResult() + } +} + /** * A conditional expression of the form `a ? b : c`, where `a` is the condition, * `b` is the expression that is evaluated if the condition evaluates to `true`, @@ -1226,7 +1243,7 @@ class VariableAssign extends VariableUpdate { } /** - * Gets the source of this assignment, if any. + * Gets the source (right-hand side) of this assignment, if any. * * An initialization in a `CatchClause` or `EnhancedForStmt` is implicit and * does not have a source. diff --git a/java/ql/src/semmle/code/java/Javadoc.qll b/java/ql/src/semmle/code/java/Javadoc.qll index 26d1bba3f93..14b59f243ec 100755 --- a/java/ql/src/semmle/code/java/Javadoc.qll +++ b/java/ql/src/semmle/code/java/Javadoc.qll @@ -79,7 +79,7 @@ abstract class JavadocElement extends @javadocElement, Top { abstract string getText(); } -/** A Javadoc tag. */ +/** A Javadoc block tag. This does not include inline tags. */ class JavadocTag extends JavadocElement, JavadocParent, @javadocTag { /** Gets the name of this Javadoc tag. */ string getTagName() { javadocTag(this, result, _, _) } diff --git a/java/ql/src/semmle/code/java/Member.qll b/java/ql/src/semmle/code/java/Member.qll index e2421c2c6f6..766c334bbf6 100755 --- a/java/ql/src/semmle/code/java/Member.qll +++ b/java/ql/src/semmle/code/java/Member.qll @@ -361,18 +361,23 @@ class Method extends Callable, @method { override MethodAccess getAReference() { result = Callable.super.getAReference() } override predicate isPublic() { - Callable.super.isPublic() or - // JLS 9.4: Every method declaration in the body of an interface is implicitly public. - getDeclaringType() instanceof Interface or + Callable.super.isPublic() + or + // JLS 9.4: Every method declaration in the body of an interface without an + // access modifier is implicitly public. + getDeclaringType() instanceof Interface and + not this.isPrivate() + or exists(FunctionalExpr func | func.asMethod() = this) } override predicate isAbstract() { Callable.super.isAbstract() or - // JLS 9.4: An interface method lacking a `default` modifier or a `static` modifier + // JLS 9.4: An interface method lacking a `private`, `default`, or `static` modifier // is implicitly abstract. this.getDeclaringType() instanceof Interface and + not this.isPrivate() and not this.isDefault() and not this.isStatic() } diff --git a/java/ql/src/semmle/code/java/PrintAst.qll b/java/ql/src/semmle/code/java/PrintAst.qll new file mode 100644 index 00000000000..0a22ab13f29 --- /dev/null +++ b/java/ql/src/semmle/code/java/PrintAst.qll @@ -0,0 +1,1005 @@ +/** + * Provides pretty-printed representations of the AST, in particular top-level + * classes and interfaces. + */ + +import java + +/** + * Holds if the pretty-printed representation of `c` has the line `s` at line + * number `line`. + */ +predicate pp(ClassOrInterface c, string s, int line) { + not c instanceof NestedType and + s = + strictconcat(string part, int i | + exists(PpAst e | getEnclosingAst*(e) = c | ppPart(e, part, line, i)) + | + part order by i + ) +} + +private PpAst getEnclosingAst(PpAst e) { + e.(Expr).getEnclosingCallable() = result or + e.(Stmt).getEnclosingCallable() = result or + e.(Member).getDeclaringType() = result or + e.(NestedType).getEnclosingType() = result +} + +/** + * An AST element to pretty-print. This is either an `Expr`, `Stmt`, `Class`, + * `Interface`, or `Member`. + * + * Subclasses specify how they are printed by giving a sequence of printable + * items. Each item in the sequence is either a string given by `getPart`, a + * line break given by `newline`, or another AST element given by `getChild`. + * The ordering of the sequence is given by the indices `i` in each of the + * three predicates. + */ +private class PpAst extends Top { + /** Gets the `i`th item to print. */ + string getPart(int i) { none() } + + /** Holds if the `i`th item to print is a line break. */ + predicate newline(int i) { none() } + + /** Gets the `i`th item to print. */ + PpAst getChild(int i) { none() } + + /** + * Holds if the `i`th item to print is a `PpAst` given by `getChild(i)` and + * that this should be indented. + */ + predicate indents(int i) { none() } +} + +/** Gets the indentation level of the AST element `e`. */ +private int indentLevel(PpAst e) { + exists(ClassOrInterface c | c = e and not c instanceof NestedType and result = 0) + or + exists(PpAst parent, int i, int lev | + e = parent.getChild(i) and + lev = indentLevel(parent) and + if parent.indents(i) then result = lev + 1 else result = lev + ) +} + +/** + * Gets the `i`th item to print belonging to `e`. This is similar to + * `e.getPart(i)`, but also include parentheses. + */ +private string getPart(PpAst e, int i) { + result = e.getPart(i) + or + e.(Expr).isParenthesized() and + ( + i = -1 + min(int j | exists(e.getPart(j)) or e.newline(j) or exists(e.getChild(j))) and + result = "(" + or + i = 1 + max(int j | exists(e.getPart(j)) or e.newline(j) or exists(e.getChild(j))) and + result = ")" + ) +} + +/** + * Gets the number of string parts contained in `e` and recursively in its + * children. + */ +language[monotonicAggregates] +private int numParts(PpAst e) { + result = + count(int i | exists(getPart(e, i))) + + sum(PpAst child | child = e.getChild(_) | numParts(child)) +} + +/** + * Gets the number of line breaks contained in `e` and recursively in its + * children. + */ +language[monotonicAggregates] +private int numLines(PpAst e) { + result = count(int i | e.newline(i)) + sum(PpAst child | child = e.getChild(_) | numLines(child)) +} + +/** + * Gets an index to a string part, line break, or child in `e` with rank `r`. + */ +private int getIndex(PpAst e, int r) { + result = rank[r](int i | exists(getPart(e, i)) or e.newline(i) or exists(e.getChild(i))) +} + +/** Holds if the `ix`th item of `e` should be printed at `(line, pos)`. */ +private predicate startPos(PpAst e, int ix, int line, int pos) { + exists(ClassOrInterface c | + c = e and not c instanceof NestedType and ix = getIndex(e, 1) and line = 0 and pos = 0 + ) + or + exists(PpAst parent, int parix | + startPos(parent, parix, line, pos) and e = parent.getChild(parix) and ix = getIndex(e, 1) + ) + or + exists(int prevIx, int r | prevIx = getIndex(e, r - 1) and ix = getIndex(e, r) | + exists(getPart(e, prevIx)) and startPos(e, prevIx, line, pos - 1) + or + e.newline(prevIx) and startPos(e, prevIx, line - 1, _) and pos = 0 + or + exists(PpAst child, int l, int p | + child = e.getChild(prevIx) and + startPos(e, prevIx, l, p) and + line = l + numLines(child) and + pos = p + numParts(child) + ) + ) +} + +/** + * Holds if the pretty-printed representation of `e` contributes `part` to occur + * on `(line, pos)`. This does not include string parts belonging to children of + * `e`. + */ +private predicate ppPart(PpAst e, string part, int line, int pos) { + exists(int i | part = getPart(e, i) and startPos(e, i, line, pos)) + or + exists(int i | exists(getPart(e, i)) or e.newline(i) | + startPos(e, i, line, 0) and + pos = -1 and + part = concat(int ind | ind in [1 .. indentLevel(e)] | " ") + ) +} + +/* + * Expressions + */ + +private class PpArrayAccess extends PpAst, ArrayAccess { + override string getPart(int i) { + i = 1 and result = "[" + or + i = 3 and result = "]" + } + + override PpAst getChild(int i) { + i = 0 and result = this.getArray() + or + i = 2 and result = this.getIndexExpr() + } +} + +private class PpArrayCreationExpr extends PpAst, ArrayCreationExpr { + override string getPart(int i) { + i = 0 and result = "new " + or + i = 1 and result = baseType() + or + i = 2 + 3 * dimensionIndex() and result = "[" + or + i = 4 + 3 * dimensionIndex() and result = "]" + or + i = 4 + 3 * exprDims() + [1 .. nonExprDims()] and result = "[]" + } + + private string baseType() { result = this.getType().(Array).getElementType().toString() } + + private int dimensionIndex() { exists(this.getDimension(result)) } + + private int exprDims() { result = max(int j | j = 0 or j = 1 + dimensionIndex()) } + + private int nonExprDims() { result = this.getType().(Array).getDimension() - exprDims() } + + override PpAst getChild(int i) { + exists(int j | result = this.getDimension(j) and i = 3 + 3 * j) + or + i = 5 + 3 * exprDims() + nonExprDims() and result = this.getInit() + } +} + +private class PpArrayInit extends PpAst, ArrayInit { + override string getPart(int i) { + i = 0 and result = "{ " + or + exists(int j | exists(this.getInit(j)) and j != 0 and i = 2 * j and result = ", ") + or + i = 2 + 2 * max(int j | exists(this.getInit(j)) or j = 0) and result = " }" + } + + override PpAst getChild(int i) { exists(int j | result = this.getInit(j) and i = 1 + 2 * j) } +} + +private class PpAssignment extends PpAst, Assignment { + override string getPart(int i) { + i = 1 and + this instanceof AssignExpr and + result = " = " + or + i = 1 and + result = " " + this.(AssignOp).getOp() + " " + } + + override PpAst getChild(int i) { + i = 0 and result = this.getDest() + or + i = 2 and result = this.getRhs() + } +} + +private class PpLiteral extends PpAst, Literal { + override string getPart(int i) { i = 0 and result = this.getLiteral() } +} + +private class PpBinaryExpr extends PpAst, BinaryExpr { + override string getPart(int i) { i = 1 and result = this.getOp() } + + override PpAst getChild(int i) { + i = 0 and result = this.getLeftOperand() + or + i = 2 and result = this.getRightOperand() + } +} + +private class PpUnaryExpr extends PpAst, UnaryExpr { + override string getPart(int i) { + i = 0 and result = "++" and this instanceof PreIncExpr + or + i = 0 and result = "--" and this instanceof PreDecExpr + or + i = 0 and result = "-" and this instanceof MinusExpr + or + i = 0 and result = "+" and this instanceof PlusExpr + or + i = 0 and result = "~" and this instanceof BitNotExpr + or + i = 0 and result = "!" and this instanceof LogNotExpr + or + i = 2 and result = "++" and this instanceof PostIncExpr + or + i = 2 and result = "--" and this instanceof PostDecExpr + } + + override PpAst getChild(int i) { i = 1 and result = this.getExpr() } +} + +private class PpCastExpr extends PpAst, CastExpr { + override string getPart(int i) { + i = 0 and result = "(" + or + i = 2 and result = ")" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getTypeExpr() + or + i = 3 and result = this.getExpr() + } +} + +private class PpCall extends PpAst, Call { + override string getPart(int i) { + i = 1 and exists(this.getQualifier()) and result = "." + or + i = 2 and + ( + result = this.(MethodAccess).getMethod().getName() + or + result = "this" and this instanceof ThisConstructorInvocationStmt + or + result = "super" and this instanceof SuperConstructorInvocationStmt + or + result = "new " and this instanceof ClassInstanceExpr and not this instanceof FunctionalExpr + or + result = "new /* -> */ " and this instanceof LambdaExpr + or + result = "new /* :: */ " and this instanceof MemberRefExpr + ) + or + i = 4 and result = "(" + or + exists(int argi | + exists(this.getArgument(argi)) and argi != 0 and i = 4 + 2 * argi and result = ", " + ) + or + i = 5 + 2 * this.getNumArgument() and result = ")" + or + i = 6 + 2 * this.getNumArgument() and result = ";" and this instanceof Stmt + or + i = 6 + 2 * this.getNumArgument() and + result = " " and + exists(this.(ClassInstanceExpr).getAnonymousClass()) + } + + override PpAst getChild(int i) { + i = 0 and result = this.getQualifier() + or + i = 3 and result = this.(ClassInstanceExpr).getTypeName() + or + exists(int argi | i = 5 + 2 * argi and result = this.getArgument(argi)) + or + i = 7 + 2 * this.getNumArgument() and result = this.(ClassInstanceExpr).getAnonymousClass() + } +} + +private class PpConditionalExpr extends PpAst, ConditionalExpr { + override string getPart(int i) { + i = 1 and result = " ? " + or + i = 3 and result = " : " + } + + override PpAst getChild(int i) { + i = 0 and result = this.getCondition() + or + i = 2 and result = this.getTrueExpr() + or + i = 4 and result = this.getFalseExpr() + } +} + +private class PpSwitchExpr extends PpAst, SwitchExpr { + override string getPart(int i) { + i = 0 and result = "switch (" + or + i = 2 and result = ") {" + or + i = 4 + 2 * count(this.getAStmt()) and result = "}" + } + + override predicate newline(int i) { i = 3 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + this.hasChildAt(result, i) + } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 4 + 2 * index) + } +} + +private class PpInstanceOfExpr extends PpAst, InstanceOfExpr { + override string getPart(int i) { + i = 1 and result = " instanceof " + or + i = 3 and result = " " and this.isPattern() + or + i = 4 and result = this.getLocalVariableDeclExpr().getName() + } + + override PpAst getChild(int i) { + i = 0 and result = this.getExpr() + or + i = 2 and result = this.getTypeName() + } +} + +private class PpLocalVariableDeclExpr extends PpAst, LocalVariableDeclExpr { + override string getPart(int i) { + i = 0 and result = this.getName() + or + i = 1 and result = " = " and exists(this.getInit()) + } + + override PpAst getChild(int i) { i = 2 and result = this.getInit() } +} + +private class PpTypeLiteral extends PpAst, TypeLiteral { + override string getPart(int i) { i = 1 and result = ".class" } + + override PpAst getChild(int i) { i = 0 and result = this.getTypeName() } +} + +private class PpThisAccess extends PpAst, ThisAccess { + override string getPart(int i) { + i = 1 and + if exists(this.getQualifier()) then result = ".this" else result = "this" + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpSuperAccess extends PpAst, SuperAccess { + override string getPart(int i) { + i = 1 and + if exists(this.getQualifier()) then result = ".super" else result = "super" + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpVarAccess extends PpAst, VarAccess { + override string getPart(int i) { + exists(string name | name = this.(VarAccess).getVariable().getName() and i = 1 | + if exists(this.getQualifier()) then result = "." + name else result = name + ) + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpTypeAccess extends PpAst, TypeAccess { + override string getPart(int i) { i = 0 and result = this.toString() } +} + +private class PpArrayTypeAccess extends PpAst, ArrayTypeAccess { + override string getPart(int i) { i = 1 and result = "[]" } + + override PpAst getChild(int i) { i = 0 and result = this.getComponentName() } +} + +private class PpUnionTypeAccess extends PpAst, UnionTypeAccess { + override string getPart(int i) { + exists(int j | i = 2 * j - 1 and j != 0 and result = " | " and exists(this.getAlternative(j))) + } + + private Expr getAlternative(int j) { result = this.getAnAlternative() and j = result.getIndex() } + + override PpAst getChild(int i) { exists(int j | i = 2 * j and result = this.getAlternative(j)) } +} + +private class PpIntersectionTypeAccess extends PpAst, IntersectionTypeAccess { + override string getPart(int i) { + exists(int j | i = 2 * j - 1 and j != 0 and result = " & " and exists(this.getBound(j))) + } + + override PpAst getChild(int i) { exists(int j | i = 2 * j and result = this.getBound(j)) } +} + +private class PpPackageAccess extends PpAst, PackageAccess { + override string getPart(int i) { i = 0 and result = "package" } +} + +private class PpWildcardTypeAccess extends PpAst, WildcardTypeAccess { + override string getPart(int i) { + i = 0 and result = "?" + or + i = 1 and result = " extends " and exists(this.getUpperBound()) + or + i = 1 and result = " super " and exists(this.getLowerBound()) + } + + override PpAst getChild(int i) { + i = 2 and result = this.getUpperBound() + or + i = 2 and result = this.getLowerBound() + } +} + +/* + * Statements + */ + +private class PpBlock extends PpAst, Block { + override string getPart(int i) { + i = 0 and result = "{" + or + i = 2 + 2 * this.getNumStmt() and result = "}" + } + + override predicate newline(int i) { i = 1 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { this.hasChildAt(result, i) } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 2 + 2 * index) + } +} + +private class PpIfStmt extends PpAst, IfStmt { + override string getPart(int i) { + i = 0 and result = "if (" + or + i = 2 and result = ")" + or + i = 3 and result = " " and this.getThen() instanceof Block + or + exists(this.getElse()) and + ( + i = 5 and result = " " and this.getThen() instanceof Block + or + i = 6 and result = "else" + or + i = 7 and result = " " and this.getElse() instanceof Block + ) + } + + override predicate newline(int i) { + i = 3 and not this.getThen() instanceof Block + or + exists(this.getElse()) and + ( + i = 5 and not this.getThen() instanceof Block + or + i = 7 and not this.getElse() instanceof Block + ) + } + + override PpAst getChild(int i) { + i = 1 and result = this.getCondition() + or + i = 4 and result = this.getThen() + or + i = 8 and result = this.getElse() + } + + override predicate indents(int i) { + i = 4 and not this.getThen() instanceof Block + or + i = 8 and not this.getElse() instanceof Block + } +} + +private class PpForStmt extends PpAst, ForStmt { + override string getPart(int i) { + i = 0 and result = "for (" + or + i = 2 and result = " " and this.getInit(0) instanceof LocalVariableDeclExpr + or + exists(int j | j > 0 and exists(this.getInit(j)) and i = 2 + 2 * j and result = ", ") + or + i = 1 + lastInitIndex() and result = "; " + or + i = 3 + lastInitIndex() and result = "; " + or + exists(int j | + j > 0 and exists(this.getUpdate(j)) and i = 3 + lastInitIndex() + 2 * j and result = ", " + ) + or + i = 1 + lastUpdateIndex() and result = ")" + or + i = 2 + lastUpdateIndex() and result = " " and this.getStmt() instanceof Block + } + + private int lastInitIndex() { result = 3 + 2 * max(int j | exists(this.getInit(j))) } + + private int lastUpdateIndex() { + result = 4 + lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j))) + } + + override predicate newline(int i) { + i = 2 + lastUpdateIndex() and not this.getStmt() instanceof Block + } + + override PpAst getChild(int i) { + i = 1 and result = this.getInit(0).(LocalVariableDeclExpr).getTypeAccess() + or + exists(int j | result = this.getInit(j) and i = 3 + 2 * j) + or + i = 2 + lastInitIndex() and result = this.getCondition() + or + exists(int j | result = this.getUpdate(j) and i = 4 + lastInitIndex() + 2 * j) + or + i = 3 + lastUpdateIndex() and result = this.getStmt() + } + + override predicate indents(int i) { + i = 3 + lastUpdateIndex() and not this.getStmt() instanceof Block + } +} + +private class PpEnhancedForStmt extends PpAst, EnhancedForStmt { + override string getPart(int i) { + i = 0 and result = "for (" + or + i = 2 and result = " " + or + i = 4 and result = " : " + or + i = 6 and + if this.getStmt() instanceof Block then result = ") " else result = ")" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getVariable().getTypeAccess() + or + i = 3 and result = this.getVariable() + or + i = 5 and result = this.getExpr() + or + i = 7 and result = this.getStmt() + } + + override predicate indents(int i) { i = 7 and not this.getStmt() instanceof Block } +} + +private class PpWhileStmt extends PpAst, WhileStmt { + override string getPart(int i) { + i = 0 and result = "while (" + or + i = 2 and result = ")" + or + i = 3 and result = " " and this.getStmt() instanceof Block + } + + override predicate newline(int i) { i = 3 and not this.getStmt() instanceof Block } + + override PpAst getChild(int i) { + i = 1 and result = this.getCondition() + or + i = 4 and result = this.getStmt() + } + + override predicate indents(int i) { i = 4 and not this.getStmt() instanceof Block } +} + +private class PpDoStmt extends PpAst, DoStmt { + override string getPart(int i) { + i = 0 and result = "do" + or + i in [1, 3] and result = " " and this.getStmt() instanceof Block + or + i = 4 and result = "while (" + or + i = 6 and result = ");" + } + + override predicate newline(int i) { i in [1, 3] and not this.getStmt() instanceof Block } + + override PpAst getChild(int i) { + i = 2 and result = this.getStmt() + or + i = 5 and result = this.getCondition() + } + + override predicate indents(int i) { i = 2 and not this.getStmt() instanceof Block } +} + +private class PpTryStmt extends PpAst, TryStmt { + override string getPart(int i) { + i = 0 and result = "try " + or + i = 1 and result = "(" and exists(this.getAResource()) + or + exists(int j | exists(this.getResourceExpr(j)) and i = 3 + 2 * j and result = ";") + or + i = 2 + lastResourceIndex() and result = ") " and exists(this.getAResource()) + or + i = 1 + lastCatchIndex() and result = " finally " and exists(this.getFinally()) + } + + private int lastResourceIndex() { + result = 2 + 2 * max(int j | exists(this.getResource(j)) or j = 0) + } + + private int lastCatchIndex() { + result = 4 + lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0) + } + + override PpAst getChild(int i) { + exists(int j | i = 2 + 2 * j and result = this.getResource(j)) + or + i = 3 + lastResourceIndex() and result = this.getBlock() + or + exists(int j | i = 4 + lastResourceIndex() + j and result = this.getCatchClause(j)) + or + i = 2 + lastCatchIndex() and result = this.getFinally() + } +} + +private class PpCatchClause extends PpAst, CatchClause { + override string getPart(int i) { + i = 0 and result = " catch (" + or + i = 2 and result = " " + or + i = 4 and result = ") " + } + + override PpAst getChild(int i) { + i = 1 and result = this.getVariable().getTypeAccess() + or + i = 3 and result = this.getVariable() + or + i = 5 and result = this.getBlock() + } +} + +private class PpSwitchStmt extends PpAst, SwitchStmt { + override string getPart(int i) { + i = 0 and result = "switch (" + or + i = 2 and result = ") {" + or + i = 4 + 2 * count(this.getAStmt()) and result = "}" + } + + override predicate newline(int i) { i = 3 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + this.hasChildAt(result, i) + } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 4 + 2 * index) + } +} + +private class PpSwitchCase extends PpAst, SwitchCase { + override string getPart(int i) { + i = 0 and result = "default" and this instanceof DefaultCase + or + i = 0 and result = "case " and this instanceof ConstCase + or + exists(int j | i = 2 * j and j != 0 and result = ", " and exists(this.(ConstCase).getValue(j))) + or + i = 1 + lastConstCaseValueIndex() and result = ":" and not this.isRule() + or + i = 1 + lastConstCaseValueIndex() and result = " -> " and this.isRule() + or + i = 3 + lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression()) + } + + private int lastConstCaseValueIndex() { + result = 1 + 2 * max(int j | j = 0 or exists(this.(ConstCase).getValue(j))) + } + + override PpAst getChild(int i) { + exists(int j | i = 1 + 2 * j and result = this.(ConstCase).getValue(j)) + or + i = 2 + lastConstCaseValueIndex() and result = this.getRuleExpression() + or + i = 2 + lastConstCaseValueIndex() and result = this.getRuleStatement() + } +} + +private class PpSynchronizedStmt extends PpAst, SynchronizedStmt { + override string getPart(int i) { + i = 0 and result = "synchronized (" + or + i = 2 and result = ")" + or + i = 3 and result = " " + } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + i = 4 and result = this.getBlock() + } +} + +private class PpReturnStmt extends PpAst, ReturnStmt { + override string getPart(int i) { + if exists(this.getResult()) + then + i = 0 and result = "return " + or + i = 2 and result = ";" + else ( + i = 0 and result = "return;" + ) + } + + override PpAst getChild(int i) { i = 1 and result = this.getResult() } +} + +private class PpThrowStmt extends PpAst, ThrowStmt { + override string getPart(int i) { + i = 0 and result = "throw " + or + i = 2 and result = ";" + } + + override PpAst getChild(int i) { i = 1 and result = this.getExpr() } +} + +private class PpBreakStmt extends PpAst, BreakStmt { + override string getPart(int i) { + i = 0 and result = "break" + or + i = 1 and result = " " and exists(this.getLabel()) + or + i = 2 and result = this.getLabel() + or + i = 3 and result = ";" + } +} + +private class PpYieldStmt extends PpAst, YieldStmt { + override string getPart(int i) { + i = 0 and result = "yield " + or + i = 2 and result = ";" + } + + override PpAst getChild(int i) { i = 1 and result = this.getValue() } +} + +private class PpContinueStmt extends PpAst, ContinueStmt { + override string getPart(int i) { + i = 0 and result = "continue" + or + i = 1 and result = " " and exists(this.getLabel()) + or + i = 2 and result = this.getLabel() + or + i = 3 and result = ";" + } +} + +private class PpEmptyStmt extends PpAst, EmptyStmt { + override string getPart(int i) { i = 0 and result = ";" } +} + +private class PpExprStmt extends PpAst, ExprStmt { + override string getPart(int i) { i = 1 and result = ";" } + + override PpAst getChild(int i) { i = 0 and result = this.getExpr() } +} + +private class PpLabeledStmt extends PpAst, LabeledStmt { + override string getPart(int i) { + i = 0 and result = this.getLabel() + or + i = 1 and result = ":" + } + + override predicate newline(int i) { i = 2 } + + override PpAst getChild(int i) { i = 3 and result = this.getStmt() } +} + +private class PpAssertStmt extends PpAst, AssertStmt { + override string getPart(int i) { + i = 0 and result = "assert " + or + i = 2 and result = " : " and exists(this.getMessage()) + or + i = 4 and result = ";" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + i = 3 and result = this.getMessage() + } +} + +private class PpLocalVariableDeclStmt extends PpAst, LocalVariableDeclStmt { + override string getPart(int i) { + i = 1 and result = " " + or + exists(int v | v > 1 and i = 2 * v - 1 and result = ", " and v = this.getAVariableIndex()) + or + i = 2 * max(this.getAVariableIndex()) + 1 and result = ";" + } + + override PpAst getChild(int i) { + i = 0 and result = this.getAVariable().getTypeAccess() + or + exists(int v | i = 2 * v and result = this.getVariable(v)) + } +} + +private class PpLocalClassDeclStmt extends PpAst, LocalClassDeclStmt { + override PpAst getChild(int i) { i = 0 and result = this.getLocalClass() } +} + +/* + * Classes, interfaces, and members + */ + +private string getMemberId(Member m) { + result = m.(Callable).getSignature() + or + result = m.getName() and not m instanceof Callable +} + +private class PpClassOrInterface extends PpAst, ClassOrInterface { + override string getPart(int i) { + not this instanceof AnonymousClass and + ( + result = getModifierPart(this, i) + or + i = 0 and result = "class " and this instanceof Class + or + i = 0 and result = "interface " and this instanceof Interface + or + i = 1 and result = this.getName() + or + i = 2 and result = " " + ) + or + i = 3 and result = "{" + or + i = 5 + 3 * max(this.memberRank(_)) and result = "}" + } + + override predicate newline(int i) { + exists(int ci | ci = 3 + 3 * this.memberRank(_) | i = ci - 1 or i = ci + 1) + } + + private int memberRank(Member member) { + member = + rank[result](Member m | + m = this.getAMember() + | + m order by m.getLocation().getStartLine(), m.getLocation().getStartColumn(), getMemberId(m) + ) + } + + override PpAst getChild(int i) { this.memberRank(result) * 3 + 3 = i } + + override predicate indents(int i) { this.memberRank(_) * 3 + 3 = i } +} + +private string getModifierPart(Modifiable m, int i) { + m.isAbstract() and result = "abstract " and i = -12 + or + m.isPublic() and result = "public " and i = -11 + or + m.isProtected() and result = "protected " and i = -10 + or + m.isPrivate() and result = "private " and i = -9 + or + m.isStatic() and result = "static " and i = -8 + or + m.isFinal() and result = "final " and i = -7 + or + m.isVolatile() and result = "volatile " and i = -6 + or + m.isSynchronized() and result = "synchronized " and i = -5 + or + m.isNative() and result = "native " and i = -4 + or + m.isDefault() and result = "default " and i = -3 + or + m.isTransient() and result = "transient " and i = -2 + or + m.isStrictfp() and result = "strictfp " and i = -1 +} + +private class PpField extends PpAst, Field { + override string getPart(int i) { + result = getModifierPart(this, i) + or + i = 0 and result = this.getType().toString() + or + i = 1 and result = " " + or + i = 2 and result = this.getName() + or + i = 3 and result = ";" + } +} + +private class PpCallable extends PpAst, Callable { + override string getPart(int i) { + result = getModifierPart(this, i) + or + i = 0 and result = this.getReturnType().toString() and this instanceof Method + or + i = 1 and result = " " and this instanceof Method + or + i = 2 and + (if this.getName() = "" then result = "" else result = this.getName()) + or + i = 3 and result = "(" + or + exists(Parameter p, int n | this.getParameter(n) = p | + i = 4 + 4 * n and result = p.getType().toString() + or + i = 5 + 4 * n and result = " " + or + i = 6 + 4 * n and result = p.getName() + or + i = 7 + 4 * n and result = ", " and n < this.getNumberOfParameters() - 1 + ) + or + i = 4 + 4 * this.getNumberOfParameters() and result = ") " + or + i = 5 + 4 * this.getNumberOfParameters() and + not exists(this.getBody()) and + result = "{ }" + } + + override PpAst getChild(int i) { + i = 5 + 4 * this.getNumberOfParameters() and result = this.getBody() + } +} diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index fa303a7c3ee..bfde273e2cb 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -117,7 +117,7 @@ class IfStmt extends ConditionalStmt, @ifstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - override Stmt getTrueSuccessor() { result = getThen() } + deprecated override Stmt getTrueSuccessor() { result = getThen() } /** Gets the `else` branch of this `if` statement. */ Stmt getElse() { result.isNthChildOf(this, 2) } @@ -168,7 +168,7 @@ class ForStmt extends ConditionalStmt, @forstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** * Gets a variable that is used as an iteration variable: it is defined, @@ -228,7 +228,7 @@ class WhileStmt extends ConditionalStmt, @whilestmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { result = "while (...) " + this.getStmt().pp() } @@ -249,7 +249,7 @@ class DoStmt extends ConditionalStmt, @dostmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { result = "do " + this.getStmt().pp() + " while (...)" } @@ -522,8 +522,8 @@ class ThrowStmt extends Stmt, @throwstmt { /** * Gets the `catch` clause that catches the exception - * thrown by this `throws` statement and occurs - * in the same method as this `throws` statement, + * thrown by this `throw` statement and occurs + * in the same method as this `throw` statement, * provided such a `catch` exists. */ CatchClause getLexicalCatchIfAny() { diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index fb2383b8e13..fac84c5c8af 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -248,8 +248,7 @@ private predicate formatStringFragment(Expr fmt) { e.(VarAccess).getVariable().getAnAssignedValue() = fmt or e.(AddExpr).getLeftOperand() = fmt or e.(AddExpr).getRightOperand() = fmt or - e.(ConditionalExpr).getTrueExpr() = fmt or - e.(ConditionalExpr).getFalseExpr() = fmt + e.(ChooseExpr).getAResultExpr() = fmt ) } @@ -293,9 +292,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) { fmtvalue = left + right ) or - formatStringValue(e.(ConditionalExpr).getTrueExpr(), fmtvalue) - or - formatStringValue(e.(ConditionalExpr).getFalseExpr(), fmtvalue) + formatStringValue(e.(ChooseExpr).getAResultExpr(), fmtvalue) or exists(Method getprop, MethodAccess ma, string prop | e = ma and diff --git a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll index ba2fd8c01c0..fc2b8a84c0f 100644 --- a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll +++ b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll @@ -213,7 +213,7 @@ private predicate hasPossibleUnknownValue(SsaVariable v) { /** * Gets a sub-expression of `e` whose value can flow to `e` through - * `ConditionalExpr`s. Parentheses are also removed. + * `ConditionalExpr`s. */ private Expr possibleValue(Expr e) { result = possibleValue(e.(ConditionalExpr).getTrueExpr()) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 7996a6d3142..1d8de8ea471 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -16,7 +16,9 @@ import semmle.code.java.frameworks.android.XmlParsing import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.JaxWS import semmle.code.java.frameworks.android.Intent -import semmle.code.java.frameworks.SpringWeb +import semmle.code.java.frameworks.spring.SpringWeb +import semmle.code.java.frameworks.spring.SpringController +import semmle.code.java.frameworks.spring.SpringWebClient import semmle.code.java.frameworks.Guice import semmle.code.java.frameworks.struts.StrutsActions import semmle.code.java.frameworks.Thrift @@ -118,7 +120,7 @@ private class SpringMultipartFileSource extends RemoteFlowSource { private class SpringServletInputParameterSource extends RemoteFlowSource { SpringServletInputParameterSource() { - this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation + this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput()) } override string getSourceType() { result = "Spring servlet input parameter" } @@ -215,6 +217,8 @@ private class RemoteTaintedMethod extends Method { this instanceof HttpServletRequestGetRequestURIMethod or this instanceof HttpServletRequestGetRequestURLMethod or this instanceof HttpServletRequestGetRemoteUserMethod or + this instanceof SpringWebRequestGetMethod or + this instanceof SpringRestTemplateResponseEntityMethod or this instanceof ServletRequestGetBodyMethod or this instanceof CookieGetValueMethod or this instanceof CookieGetNameMethod or @@ -232,6 +236,22 @@ private class RemoteTaintedMethod extends Method { } } +private class SpringWebRequestGetMethod extends Method { + SpringWebRequestGetMethod() { + exists(SpringWebRequest swr | this = swr.getAMethod() | + this.hasName("getDescription") or + this.hasName("getHeader") or + this.hasName("getHeaderNames") or + this.hasName("getHeaderValues") or + this.hasName("getParameter") or + this.hasName("getParameterMap") or + this.hasName("getParameterNames") or + this.hasName("getParameterValues") + // TODO consider getRemoteUser + ) + } +} + private class EnvTaintedMethod extends Method { EnvTaintedMethod() { this instanceof MethodSystemGetenv or diff --git a/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll b/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll index 29e2b3ec8a1..150721b574c 100644 --- a/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll +++ b/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll @@ -10,8 +10,7 @@ private import RangeAnalysis /** Gets an expression that might have the value `i`. */ private Expr exprWithIntValue(int i) { result.(ConstantIntegerExpr).getIntValue() = i or - result.(ConditionalExpr).getTrueExpr() = exprWithIntValue(i) or - result.(ConditionalExpr).getFalseExpr() = exprWithIntValue(i) + result.(ChooseExpr).getAResultExpr() = exprWithIntValue(i) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/Nullness.qll b/java/ql/src/semmle/code/java/dataflow/Nullness.qll index 1679ce6b9b9..56433cb009f 100644 --- a/java/ql/src/semmle/code/java/dataflow/Nullness.qll +++ b/java/ql/src/semmle/code/java/dataflow/Nullness.qll @@ -45,8 +45,7 @@ private import semmle.code.java.frameworks.Assertions /** Gets an expression that may be `null`. */ Expr nullExpr() { result instanceof NullLiteral or - result.(ConditionalExpr).getTrueExpr() = nullExpr() or - result.(ConditionalExpr).getFalseExpr() = nullExpr() or + result.(ChooseExpr).getAResultExpr() = nullExpr() or result.(AssignExpr).getSource() = nullExpr() or result.(CastExpr).getExpr() = nullExpr() } @@ -81,9 +80,7 @@ private predicate unboxed(Expr e) { or exists(UnaryExpr un | un.getExpr() = e) or - exists(ConditionalExpr cond | cond.getType() instanceof PrimitiveType | - cond.getTrueExpr() = e or cond.getFalseExpr() = e - ) + exists(ChooseExpr cond | cond.getType() instanceof PrimitiveType | cond.getAResultExpr() = e) or exists(ConditionNode cond | cond.getCondition() = e) or diff --git a/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll b/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll index 60758069232..595f9c623f2 100644 --- a/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll +++ b/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll @@ -552,9 +552,7 @@ private Sign exprSign(Expr e) { result = s1.urshift(s2) ) or - result = exprSign(e.(ConditionalExpr).getTrueExpr()) - or - result = exprSign(e.(ConditionalExpr).getFalseExpr()) + result = exprSign(e.(ChooseExpr).getAResultExpr()) or result = exprSign(e.(CastExpr).getExpr()) ) diff --git a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll index b5cea656a38..7ff2c872111 100644 --- a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll @@ -72,9 +72,7 @@ private predicate privateParamArg(Parameter p, Argument arg) { * necessarily functionally determined by `n2`. */ private predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2) { - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or exists(Field f, Expr e | f = n2.asField() and @@ -226,9 +224,8 @@ private predicate upcastCand(TypeFlowNode n, RefType t, RefType t1, RefType t2) or exists(Parameter p | privateParamArg(p, n.asExpr()) and t2 = p.getType().getErasure()) or - exists(ConditionalExpr cond | - cond.getTrueExpr() = n.asExpr() or cond.getFalseExpr() = n.asExpr() - | + exists(ChooseExpr cond | + cond.getAResultExpr() = n.asExpr() and t2 = cond.getType().getErasure() ) ) @@ -308,6 +305,21 @@ private predicate instanceOfGuarded(VarAccess va, RefType t) { ) } +/** + * Holds if `aa` is an access to a value that is guarded by `instanceof t`. + */ +predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) { + exists(InstanceOfExpr ioe, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 | + ioe.getExpr() = aa1 and + t = ioe.getTypeName().getType() and + aa1.getArray() = v1.getAUse() and + aa1.getIndexExpr() = v2.getAUse() and + aa.getArray() = v1.getAUse() and + aa.getIndexExpr() = v2.getAUse() and + guardControls_v1(ioe, aa.getBasicBlock(), true) + ) +} + /** * Holds if `n` has type `t` and this information is discarded, such that `t` * might be a better type bound for nodes where `n` flows to. @@ -318,6 +330,7 @@ private predicate typeFlowBase(TypeFlowNode n, RefType t) { upcastEnhancedForStmt(n.asSsa(), srctype) or downcastSuccessor(n.asExpr(), srctype) or instanceOfGuarded(n.asExpr(), srctype) or + arrayInstanceOfGuarded(n.asExpr(), srctype) or n.asExpr().(FunctionalExpr).getConstructedType() = srctype | t = srctype.(BoundedType).getAnUltimateUpperBoundType() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 566ec3a45e7..af8b44d5df8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -89,45 +89,95 @@ class ContainerType extends RefType { } private predicate taintPreservingQualifierToMethod(Method m) { + // java.util.Map.Entry m.getDeclaringType() instanceof EntryType and - m.hasName("getValue") + m.hasName(["getValue", "setValue"]) or + // java.util.Iterable m.getDeclaringType() instanceof IterableType and - m.hasName("iterator") + m.hasName(["iterator", "spliterator"]) or + // java.util.Iterator m.getDeclaringType() instanceof IteratorType and m.hasName("next") or + // java.util.ListIterator + m.getDeclaringType() instanceof IteratorType and + m.hasName("previous") + or + // java.util.Enumeration m.getDeclaringType() instanceof EnumerationType and - m.hasName("nextElement") + m.hasName(["asIterator", "nextElement"]) or - m.(MapMethod).hasName("entrySet") + // java.util.Map + m + .(MapMethod) + .hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "put", "putIfAbsent", + "remove", "replace", "values"]) or - m.(MapMethod).hasName("get") + // java.util.Collection + m.(CollectionMethod).hasName(["parallelStream", "stream", "toArray"]) or - m.(MapMethod).hasName("remove") - or - m.(MapMethod).hasName("values") - or - m.(CollectionMethod).hasName("toArray") - or - m.(CollectionMethod).hasName("get") + // java.util.List + m.(CollectionMethod).hasName(["get", "listIterator", "set", "subList"]) or m.(CollectionMethod).hasName("remove") and m.getParameterType(0).(PrimitiveType).hasName("int") or + // java.util.Vector + m.(CollectionMethod).hasName(["elementAt", "elements", "firstElement", "lastElement"]) + or + // java.util.Stack + m.(CollectionMethod).hasName(["peek", "pop"]) + or + // java.util.Queue + m.(CollectionMethod).hasName(["element", "poll"]) + or m.(CollectionMethod).hasName("remove") and m.getNumberOfParameters() = 0 or - m.(CollectionMethod).hasName("subList") + // java.util.Deque + m + .(CollectionMethod) + .hasName(["getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast", + "removeFirst", "removeLast"]) or - m.(CollectionMethod).hasName("firstElement") + // java.util.concurrent.BlockingQueue + // covered by Queue: poll(long, TimeUnit) + m.(CollectionMethod).hasName("take") or - m.(CollectionMethod).hasName("lastElement") + // java.util.concurrent.BlockingDeque + // covered by Deque: pollFirst(long, TimeUnit), pollLast(long, TimeUnit) + m.(CollectionMethod).hasName(["takeFirst", "takeLast"]) or - m.(CollectionMethod).hasName("poll") + // java.util.SortedSet + m.(CollectionMethod).hasName(["first", "headSet", "last", "subSet", "tailSet"]) or - m.(CollectionMethod).hasName("peek") + // java.util.NavigableSet + // covered by Deque: pollFirst(), pollLast() + // covered by SortedSet: headSet(E, boolean), subSet(E, boolean, E, boolean) and tailSet(E, boolean) + m + .(CollectionMethod) + .hasName(["ceiling", "descendingIterator", "descendingSet", "floor", "higher", "lower"]) or - m.(CollectionMethod).hasName("element") + // java.util.SortedMap + m.(MapMethod).hasName(["headMap", "subMap", "tailMap"]) + or + // java.util.NavigableMap + // covered by SortedMap: headMap(K, boolean), subMap(K, boolean, K, boolean), tailMap(K, boolean) + m + .(MapMethod) + .hasName(["ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry", + "lastEntry", "lowerEntry", "pollFirstEntry", "pollLastEntry"]) + or + // java.util.Dictionary + m + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + m.hasName(["elements", "get", "put", "remove"]) + or + // java.util.concurrent.ConcurrentHashMap + m.(MapMethod).hasName(["elements", "search", "searchEntries", "searchValues"]) } private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { @@ -135,28 +185,165 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { tracked = sink.getQualifier() } -private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { - exists(MethodAccess ma | - ma.getMethod().(CollectionMethod).hasName("toArray") and +private predicate qualifierToArgumentStep(Expr tracked, Expr sink) { + exists(MethodAccess ma, CollectionMethod method | + method = ma.getMethod() and + ( + // java.util.Vector + method.hasName("copyInto") + or + // java.util.concurrent.BlockingQueue + method.hasName("drainTo") + or + // java.util.Collection + method.hasName("toArray") and method.getParameter(0).getType() instanceof Array + ) and tracked = ma.getQualifier() and - sink = ma.getArgument(1) + sink = ma.getArgument(0) ) } private predicate taintPreservingArgumentToQualifier(Method method, int arg) { - method.(MapMethod).hasName("put") and arg = 1 + // java.util.Map.Entry + method.getDeclaringType() instanceof EntryType and + method.hasName("setValue") and + arg = 0 + or + // java.util.Map + method.(MapMethod).hasName(["merge", "put", "putIfAbsent"]) and arg = 1 + or + method.(MapMethod).hasName("replace") and arg = method.getNumberOfParameters() - 1 or method.(MapMethod).hasName("putAll") and arg = 0 or - method.(CollectionMethod).hasName("add") and arg = method.getNumberOfParameters() - 1 + // java.util.ListIterator + method.getDeclaringType() instanceof IteratorType and + method.hasName(["add", "set"]) and + arg = 0 or - method.(CollectionMethod).hasName("addAll") and arg = method.getNumberOfParameters() - 1 - or - method.(CollectionMethod).hasName("addElement") and arg = 0 + // java.util.Collection + method.(CollectionMethod).hasName(["add", "addAll"]) and + // Refer to the last parameter to also cover List::add(int, E) and List::addAll(int, Collection) + arg = method.getNumberOfParameters() - 1 or + // java.util.List + // covered by Collection: add(int, E), addAll(int, Collection) method.(CollectionMethod).hasName("set") and arg = 1 or + // java.util.Vector + method.(CollectionMethod).hasName(["addElement", "insertElementAt", "setElementAt"]) and arg = 0 + or + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or + // java.util.Queue method.(CollectionMethod).hasName("offer") and arg = 0 + or + // java.util.Deque + // covered by Stack: push(E) + method.(CollectionMethod).hasName(["addFirst", "addLast", "offerFirst", "offerLast"]) and arg = 0 + or + // java.util.concurrent.BlockingQueue + // covered by Queue: offer(E, long, TimeUnit) + method.(CollectionMethod).hasName("put") and arg = 0 + or + // java.util.concurrent.TransferQueue + method.(CollectionMethod).hasName(["transfer", "tryTransfer"]) and arg = 0 + or + // java.util.concurrent.BlockingDeque + // covered by Deque: offerFirst(E, long, TimeUnit), offerLast(E, long, TimeUnit) + method.(CollectionMethod).hasName(["putFirst", "putLast"]) and arg = 0 + or + //java.util.Dictionary + method + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + method.hasName("put") and + arg = 1 +} + +/** + * Holds if `method` is a library method that returns tainted data if its + * `arg`th argument is tainted. + */ +private predicate taintPreservingArgumentToMethod(Method method, int arg) { + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + ( + method + .hasName(["checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap", + "checkedNavigableSet", "checkedSet", "checkedSortedMap", "checkedSortedSet", + "enumeration", "list", "max", "min", "singleton", "singletonList", + "synchronizedCollection", "synchronizedList", "synchronizedMap", + "synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet", + "synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection", + "unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap", + "unmodifiableNavigableSet", "unmodifiableSet", "unmodifiableSortedMap", + "unmodifiableSortedSet"]) and + arg = 0 + or + method.hasName(["nCopies", "singletonMap"]) and arg = 1 + ) + or + method + .getDeclaringType() + .getSourceDeclaration() + .hasQualifiedName("java.util", ["List", "Map", "Set"]) and + method.hasName("copyOf") and + arg = 0 + or + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", "Map") and + ( + method.hasName("of") and + arg = any(int i | i in [1 .. 10] | 2 * i - 1) + or + method.hasName("entry") and + arg = 1 + ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName(["copyOf", "copyOfRange", "spliterator", "stream"]) and + arg = 0 + ) +} + +/** + * Holds if `method` is a library method that returns tainted data if any + * of its arguments are tainted. + */ +private predicate taintPreservingArgumentToMethod(Method method) { + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", ["Set", "List"]) and + method.hasName("of") + or + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", "Map") and + method.hasName("ofEntries") +} + +/** + * Holds if `method` is a library method that writes tainted data to the + * `output`th argument if the `input`th argument is tainted. + */ +private predicate taintPreservingArgToArg(Method method, int input, int output) { + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + ( + method.hasName(["copy", "fill"]) and + input = 1 and + output = 0 + or + method.hasName("replaceAll") and input = 2 and output = 0 + ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName("fill") and + output = 0 and + input = method.getNumberOfParameters() - 1 + ) } private predicate argToQualifierStep(Expr tracked, Expr sink) { @@ -168,13 +355,55 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { ) } +/** Access to a method that passes taint from an argument. */ +private predicate argToMethodStep(Expr tracked, MethodAccess sink) { + exists(Method m | + m = sink.getMethod() and + ( + exists(int i | + taintPreservingArgumentToMethod(m, i) and + tracked = sink.getArgument(i) + ) + or + m.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + m.hasName("asList") and + tracked = sink.getAnArgument() + ) + ) + or + taintPreservingArgumentToMethod(sink.getMethod()) and + tracked = sink.getAnArgument() +} + +/** + * Holds if `tracked` and `sink` are arguments to a method that transfers taint + * between arguments. + */ +private predicate argToArgStep(Expr tracked, Expr sink) { + exists(MethodAccess ma, Method method, int input, int output | + ma.getMethod() = method and + ma.getArgument(input) = tracked and + ma.getArgument(output) = sink and + ( + taintPreservingArgToArg(method, input, output) + or + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + method.hasName("addAll") and + input >= 1 and + output = 0 + ) + ) +} + /** * Holds if the step from `n1` to `n2` is either extracting a value from a * container, inserting a value into a container, or transforming one container * to another. This is restricted to cases where `n2` is the returned value of * a call. */ -predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, n2) } +predicate containerReturnValueStep(Expr n1, Expr n2) { + qualifierToMethodStep(n1, n2) or argToMethodStep(n1, n2) +} /** * Holds if the step from `n1` to `n2` is either extracting a value from a @@ -183,7 +412,8 @@ predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, */ predicate containerUpdateStep(Expr n1, Expr n2) { qualifierToArgumentStep(n1, n2) or - argToQualifierStep(n1, n2) + argToQualifierStep(n1, n2) or + argToArgStep(n1, n2) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll index a0a03cf4cc7..97b83352492 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -2,14 +2,13 @@ private import java private import DataFlowPrivate import semmle.code.java.dispatch.VirtualDispatch -cached private module DispatchImpl { /** * Holds if the set of viable implementations that can be called by `ma` * might be improved by knowing the call context. This is the case if the * qualifier is the `i`th parameter of the enclosing callable `c`. */ - private predicate benefitsFromCallContext(MethodAccess ma, Callable c, int i) { + private predicate mayBenefitFromCallContext(MethodAccess ma, Callable c, int i) { exists(Parameter p | 2 <= strictcount(viableImpl(ma)) and ma.getQualifier().(VarAccess).getVariable() = p and @@ -28,7 +27,7 @@ private module DispatchImpl { pragma[nomagic] private predicate relevantContext(Call ctx, int i) { exists(Callable c | - benefitsFromCallContext(_, c, i) and + mayBenefitFromCallContext(_, c, i) and c = viableCallable(ctx) ) } @@ -53,14 +52,23 @@ private module DispatchImpl { ) } + /** + * Holds if the set of viable implementations that can be called by `ma` + * might be improved by knowing the call context. This is the case if the + * qualifier is a parameter of the enclosing callable `c`. + */ + predicate mayBenefitFromCallContext(MethodAccess ma, Callable c) { + mayBenefitFromCallContext(ma, c, _) + } + /** * Gets a viable dispatch target of `ma` in the context `ctx`. This is * restricted to those `ma`s for which a context might make a difference. */ - private Method viableImplInCallContext(MethodAccess ma, Call ctx) { + Method viableImplInCallContext(MethodAccess ma, Call ctx) { result = viableImpl(ma) and exists(int i, Callable c, Method def, RefType t, boolean exact | - benefitsFromCallContext(ma, c, i) and + mayBenefitFromCallContext(ma, c, i) and c = viableCallable(ctx) and contextArgHasType(ctx, i, t, exact) and ma.getMethod() = def @@ -136,57 +144,6 @@ private module DispatchImpl { ) ) } - - /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. - */ - cached - predicate reducedViableImplInCallContext(MethodAccess ma, Callable c, Call ctx) { - exists(int tgts, int ctxtgts | - benefitsFromCallContext(ma, c, _) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(ma, ctx)) and - tgts = strictcount(viableImpl(ma)) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. - */ - cached - Method prunedViableImplInCallContext(MethodAccess ma, Call ctx) { - result = viableImplInCallContext(ma, ctx) and - reducedViableImplInCallContext(ma, _, ctx) - } - - /** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ - cached - predicate reducedViableImplInReturn(Method m, MethodAccess ma) { - exists(int tgts, int ctxtgts | - benefitsFromCallContext(ma, _, _) and - m = viableImpl(ma) and - ctxtgts = count(Call ctx | m = viableImplInCallContext(ma, ctx)) and - tgts = strictcount(Call ctx | viableCallable(ctx) = ma.getEnclosingCallable()) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ - cached - Method prunedViableImplInCallContextReverse(MethodAccess ma, Call ctx) { - result = viableImplInCallContext(ma, ctx) and - reducedViableImplInReturn(result, ma) - } } import DispatchImpl diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index db0fbcf7130..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } @@ -289,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -420,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1049,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1060,10 +1073,10 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1077,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1111,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1125,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1157,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1186,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1200,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1226,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1525,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1540,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1551,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1561,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1569,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1647,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1675,21 +1698,18 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1733,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1895,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1927,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2044,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2101,14 +2132,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2183,7 +2231,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2220,7 +2268,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2254,12 +2302,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2318,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2574,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2586,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2597,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2615,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2594,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2611,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2724,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2740,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2749,11 +2799,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2823,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index b241a574c97..27ab1d01feb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,13 +289,94 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) + ) } /** @@ -340,21 +387,10 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,26 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -564,6 +615,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +637,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +649,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +663,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } @@ -665,9 +730,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -679,6 +741,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -689,25 +768,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 90f443e5578..93cb973b771 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -129,15 +129,6 @@ private predicate instanceFieldAssign(Expr src, FieldAccess fa) { ) } -/** - * Gets an upper bound on the type of `f`. - */ -private Type getFieldTypeBound(Field f) { - fieldTypeFlow(f, result, _) - or - not fieldTypeFlow(f, _, _) and result = f.getType() -} - private newtype TContent = TFieldContent(InstanceField f) or TCollectionContent() or @@ -154,12 +145,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the erased type of the object containing this content. */ - abstract DataFlowType getContainerType(); - - /** Gets the erased type of this content. */ - abstract DataFlowType getType(); } private class FieldContent extends Content, TFieldContent { @@ -174,26 +159,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override DataFlowType getContainerType() { result = getErasedRepr(f.getDeclaringType()) } - - override DataFlowType getType() { result = getErasedRepr(getFieldTypeBound(f)) } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override DataFlowType getContainerType() { none() } - - override DataFlowType getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override DataFlowType getContainerType() { none() } - - override DataFlowType getType() { none() } } /** @@ -222,12 +195,21 @@ predicate readStep(Node node1, Content f, Node node2) { ) } +/** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ +predicate clearsContent(Node n, Content c) { + n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() +} + /** * Gets a representative (boxed) type for `t` for the purpose of pruning * possible flow. A single type is used for all numeric types to account for * numeric conversions, and otherwise the erasure is used. */ -DataFlowType getErasedRepr(Type t) { +private DataFlowType getErasedRepr(Type t) { exists(Type e | e = t.getErasure() | if e instanceof NumericOrCharType then result.(BoxedType).getPrimitiveType().getName() = "double" @@ -240,6 +222,9 @@ DataFlowType getErasedRepr(Type t) { t instanceof NullType and result instanceof TypeObject } +pragma[noinline] +DataFlowType getNodeType(Node n) { result = getErasedRepr(n.getTypeBound()) } + /** Gets a string representation of a type returned by `getErasedRepr`. */ string ppReprType(Type t) { if t.(BoxedType).getPrimitiveType().getName() = "double" @@ -338,3 +323,6 @@ int accessPathLimit() { result = 5 } predicate isImmutableOrUnobservable(Node n) { n.getType() instanceof ImmutableType or n instanceof ImplicitVarargsArray } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll index 74b492f76bb..8434d74d839 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -397,11 +397,22 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { or node2.asExpr().(CastExpr).getExpr() = node1.asExpr() or - node2.asExpr().(ConditionalExpr).getTrueExpr() = node1.asExpr() - or - node2.asExpr().(ConditionalExpr).getFalseExpr() = node1.asExpr() + node2.asExpr().(ChooseExpr).getAResultExpr() = node1.asExpr() or node2.asExpr().(AssignExpr).getSource() = node1.asExpr() + or + exists(MethodAccess ma, Method m | + ma = node2.asExpr() and + m = ma.getMethod() and + m.getDeclaringType().hasQualifiedName("java.util", "Objects") and + ( + m.hasName(["requireNonNull", "requireNonNullElseGet"]) and node1.asExpr() = ma.getArgument(0) + or + m.hasName("requireNonNullElse") and node1.asExpr() = ma.getAnArgument() + or + m.hasName("toString") and node1.asExpr() = ma.getArgument(1) + ) + ) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index a1aa335fefc..b9ae1e7ecd1 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -8,6 +8,8 @@ private import semmle.code.java.security.Validation private import semmle.code.java.frameworks.android.Intent private import semmle.code.java.frameworks.Guice private import semmle.code.java.frameworks.Protobuf +private import semmle.code.java.frameworks.spring.SpringController +private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.Maps private import semmle.code.java.dataflow.internal.ContainerFlow private import semmle.code.java.frameworks.jackson.JacksonSerializability @@ -252,6 +254,22 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) { or // a custom InputStream that wraps a tainted data source is tainted inputStreamWrapper(sink.getConstructor(), argi) + or + // A SpringHttpEntity is a wrapper around a body and some headers + // Track flow through iff body is a String + exists(SpringHttpEntity she | + sink.getConstructor() = she.getAConstructor() and + argi = 0 and + tracked.getType() instanceof TypeString + ) + or + // A SpringRequestEntity is a wrapper around a body and some headers + // Track flow through iff body is a String + exists(SpringResponseEntity sre | + sink.getConstructor() = sre.getAConstructor() and + argi = 0 and + tracked.getType() instanceof TypeString + ) ) } @@ -292,10 +310,13 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { * Methods that return tainted data when called on tainted data. */ private predicate taintPreservingQualifierToMethod(Method m) { + m instanceof CloneMethod + or m.getDeclaringType() instanceof TypeString and ( m.getName() = "concat" or m.getName() = "endsWith" or + m.getName() = "formatted" or m.getName() = "getBytes" or m.getName() = "split" or m.getName() = "substring" or @@ -321,7 +342,11 @@ private predicate taintPreservingQualifierToMethod(Method m) { ) or m.getDeclaringType().getQualifiedName().matches("%StringWriter") and - m.getName() = "toString" + ( + m.getName() = "getBuffer" + or + m.getName() = "toString" + ) or m.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and m.getName().matches("next%") @@ -334,7 +359,8 @@ private predicate taintPreservingQualifierToMethod(Method m) { or ( m.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or - m.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer") + m.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer") or + m.getDeclaringType().hasQualifiedName("java.io", "StringWriter") ) and (m.getName() = "toString" or m.getName() = "append") or @@ -352,6 +378,21 @@ private predicate taintPreservingQualifierToMethod(Method m) { m = any(GuiceProvider gp).getAnOverridingGetMethod() or m = any(ProtobufMessageLite p).getAGetterMethod() + or + m instanceof GetterMethod and m.getDeclaringType() instanceof SpringUntrustedDataType + or + m.getDeclaringType() instanceof SpringHttpEntity and + m.getName().regexpMatch("getBody|getHeaders") + or + exists(SpringHttpHeaders headers | m = headers.getAMethod() | + m.getReturnType() instanceof TypeString + or + exists(ParameterizedType stringlist | + m.getReturnType().(RefType).getASupertype*() = stringlist and + stringlist.getSourceDeclaration().hasQualifiedName("java.util", "List") and + stringlist.getTypeArgument(0) instanceof TypeString + ) + ) } private class StringReplaceMethod extends Method { @@ -377,9 +418,9 @@ private predicate unsafeEscape(MethodAccess ma) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { exists(Method m, int i | - m = sink.(MethodAccess).getMethod() and + m = sink.getMethod() and taintPreservingArgumentToMethod(m, i) and - tracked = sink.(MethodAccess).getArgument(i) + tracked = sink.getArgument(i) ) or exists(MethodAccess ma | @@ -387,6 +428,22 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { tracked = ma.getAnArgument() and sink = ma ) + or + exists(Method springResponseEntityOfOk | + sink.getMethod() = springResponseEntityOfOk and + springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and + springResponseEntityOfOk.getName().regexpMatch("ok|of") and + tracked = sink.getArgument(0) and + tracked.getType() instanceof TypeString + ) + or + exists(Method springResponseEntityBody | + sink.getMethod() = springResponseEntityBody and + springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and + springResponseEntityBody.getName().regexpMatch("body") and + tracked = sink.getArgument(0) and + tracked.getType() instanceof TypeString + ) } /** @@ -395,7 +452,7 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { */ private predicate taintPreservingArgumentToMethod(Method method) { method.getDeclaringType() instanceof TypeString and - (method.hasName("format") or method.hasName("join")) + (method.hasName("format") or method.hasName("formatted") or method.hasName("join")) } /** @@ -434,7 +491,15 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or ( method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or - method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder") + method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder") or + method + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("org.apache.commons.codec", "Encoder") or + method + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("org.apache.commons.codec", "Decoder") ) and ( method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1 @@ -497,6 +562,10 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { method instanceof JacksonWriteValueMethod and method.getNumberOfParameters() = 1 and arg = 0 + or + method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and + method.hasName("append") and + arg = 0 } /** @@ -571,9 +640,20 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { private predicate taintPreservingArgumentToQualifier(Method method, int arg) { exists(Method write | method.overrides*(write) and - write.getDeclaringType().hasQualifiedName("java.io", "OutputStream") and write.hasName("write") and - arg = 0 + arg = 0 and + ( + write.getDeclaringType().hasQualifiedName("java.io", "OutputStream") + or + write.getDeclaringType().hasQualifiedName("java.io", "StringWriter") + ) + ) + or + exists(Method append | + method.overrides*(append) and + append.hasName("append") and + arg = 0 and + append.getDeclaringType().hasQualifiedName("java.io", "StringWriter") ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..af0d0fec53a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll index 0ef6da8b150..28de0cf8eed 100644 --- a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll +++ b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll @@ -202,9 +202,7 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) { or n2.asExpr().(CastExpr).getExpr() = n1.asExpr() or - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or n2.asExpr().(AssignExpr).getSource() = n1.asExpr() or diff --git a/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll b/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll index 11537ac144b..52ee910ae1d 100644 --- a/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll +++ b/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll @@ -100,9 +100,7 @@ private predicate step(Node n1, Node n2) { or n2.asExpr().(CastExpr).getExpr() = n1.asExpr() or - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or n2.asExpr().(AssignExpr).getSource() = n1.asExpr() or diff --git a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll index a0388460acb..833db9a9e44 100644 --- a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll +++ b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll @@ -1,31 +1,50 @@ +/** + * Provides classes and predicates for working with annotations in the `javax` package. + */ + import java /* - * javax.annotation annotations + * Annotations in the package `javax.annotation`. */ +/** + * A `@javax.annotation.Generated` annotation. + */ class GeneratedAnnotation extends Annotation { GeneratedAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Generated") } } +/** + * A `@javax.annotation.PostConstruct` annotation. + */ class PostConstructAnnotation extends Annotation { PostConstructAnnotation() { this.getType().hasQualifiedName("javax.annotation", "PostConstruct") } } +/** + * A `@javax.annotation.PreDestroy` annotation. + */ class PreDestroyAnnotation extends Annotation { PreDestroyAnnotation() { this.getType().hasQualifiedName("javax.annotation", "PreDestroy") } } +/** + * A `@javax.annotation.Resource` annotation. + */ class ResourceAnnotation extends Annotation { ResourceAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Resource") } } +/** + * A `@javax.annotation.Resources` annotation. + */ class ResourcesAnnotation extends Annotation { ResourcesAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Resources") } } /** - * A javax.annotation.ManagedBean annotation. + * A `@javax.annotation.ManagedBean` annotation. */ class JavaxManagedBeanAnnotation extends Annotation { JavaxManagedBeanAnnotation() { @@ -34,71 +53,104 @@ class JavaxManagedBeanAnnotation extends Annotation { } /* - * javax.annotation.security annotations + * Annotations in the package `javax.annotation.security`. */ +/** + * A `@javax.annotation.security.DeclareRoles` annotation. + */ class DeclareRolesAnnotation extends Annotation { DeclareRolesAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "DeclareRoles") } } +/** + * A `@javax.annotation.security.DenyAll` annotation. + */ class DenyAllAnnotation extends Annotation { DenyAllAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "DenyAll") } } +/** + * A `@javax.annotation.security.PermitAll` annotation. + */ class PermitAllAnnotation extends Annotation { PermitAllAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "PermitAll") } } +/** + * A `@javax.annotation.security.RolesAllowed` annotation. + */ class RolesAllowedAnnotation extends Annotation { RolesAllowedAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "RolesAllowed") } } +/** + * A `@javax.annotation.security.RunAs` annotation. + */ class RunAsAnnotation extends Annotation { RunAsAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "RunAs") } } /* - * javax.interceptor annotations + * Annotations in the package `javax.interceptor`. */ +/** + * A `@javax.interceptor.AroundInvoke` annotation. + */ class AroundInvokeAnnotation extends Annotation { AroundInvokeAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "AroundInvoke") } } +/** + * A `@javax.interceptor.ExcludeClassInterceptors` annotation. + */ class ExcludeClassInterceptorsAnnotation extends Annotation { ExcludeClassInterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "ExcludeClassInterceptors") } } +/** + * A `@javax.interceptor.ExcludeDefaultInterceptors` annotation. + */ class ExcludeDefaultInterceptorsAnnotation extends Annotation { ExcludeDefaultInterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "ExcludeDefaultInterceptors") } } +/** + * A `@javax.interceptor.Interceptors` annotation. + */ class InterceptorsAnnotation extends Annotation { InterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "Interceptors") } } /* - * javax.jws annotations + * Annotations in the package `javax.jws`. */ +/** + * A `@javax.jws.WebService` annotation. + */ class WebServiceAnnotation extends Annotation { WebServiceAnnotation() { this.getType().hasQualifiedName("javax.jws", "WebService") } } /* - * javax.xml.ws annotations + * Annotations in the package `javax.xml.ws`. */ +/** + * A `@javax.xml.ws.WebServiceRef` annotation. + */ class WebServiceRefAnnotation extends Annotation { WebServiceRefAnnotation() { this.getType().hasQualifiedName("javax.xml.ws", "WebServiceRef") } } diff --git a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll index 8f3fafb5540..a011af98cd5 100644 --- a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll @@ -1,19 +1,3 @@ import java - -/** A Spring framework annotation indicating remote user input from servlets. */ -class SpringServletInputAnnotation extends Annotation { - SpringServletInputAnnotation() { - exists(AnnotationType a | - a = this.getType() and - a.getPackage().getName() = "org.springframework.web.bind.annotation" - | - a.hasName("MatrixVariable") or - a.hasName("RequestParam") or - a.hasName("RequestHeader") or - a.hasName("CookieValue") or - a.hasName("RequestPart") or - a.hasName("PathVariable") or - a.hasName("RequestBody") - ) - } -} +import spring.SpringController +import spring.SpringWeb diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll index c704320657f..93d79813e39 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with the GWT framework. */ + import java import GwtXml import GwtUiBinder diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll index c74bc83915f..dc8aa0b1ba6 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll @@ -8,26 +8,44 @@ import java import GwtUiBinderXml +/** + * An annotation in the package `com.google.gwt.uibinder.client`. + */ class GwtUiBinderClientAnnotation extends Annotation { GwtUiBinderClientAnnotation() { getType().getPackage().hasName("com.google.gwt.uibinder.client") } } +/** + * A `@com.google.gwt.uibinder.client.UiHandler` annotation. + */ class GwtUiHandlerAnnotation extends GwtUiBinderClientAnnotation { GwtUiHandlerAnnotation() { getType().hasName("UiHandler") } } +/** + * A `@com.google.gwt.uibinder.client.UiField` annotation. + */ class GwtUiFieldAnnotation extends GwtUiBinderClientAnnotation { GwtUiFieldAnnotation() { getType().hasName("UiField") } } +/** + * A `@com.google.gwt.uibinder.client.UiTemplate` annotation. + */ class GwtUiTemplateAnnotation extends GwtUiBinderClientAnnotation { GwtUiTemplateAnnotation() { getType().hasName("UiTemplate") } } +/** + * A `@com.google.gwt.uibinder.client.UiFactory` annotation. + */ class GwtUiFactoryAnnotation extends GwtUiBinderClientAnnotation { GwtUiFactoryAnnotation() { getType().hasName("UiFactory") } } +/** + * A `@com.google.gwt.uibinder.client.UiConstructor` annotation. + */ class GwtUiConstructorAnnotation extends GwtUiBinderClientAnnotation { GwtUiConstructorAnnotation() { getType().hasName("UiConstructor") } } diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll index 287d2d778da..482d5d70e93 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with `*.gwt.xml` files. */ + import semmle.code.xml.XML /** diff --git a/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll b/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll index 9e3ef1144a7..df8ba507f9f 100644 --- a/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll +++ b/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with OCNI (Objective-C Native Interface). + */ + import java /** diff --git a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll index 406cf35dcf7..99d73367162 100644 --- a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll +++ b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll @@ -9,6 +9,9 @@ import semmle.code.java.Reflection import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow5 +/** + * A `@com.fasterxml.jackson.annotation.JsonIgnore` annoation. + */ class JacksonJSONIgnoreAnnotation extends NonReflectiveAnnotation { JacksonJSONIgnoreAnnotation() { exists(AnnotationType anntp | anntp = this.getType() | @@ -17,6 +20,7 @@ class JacksonJSONIgnoreAnnotation extends NonReflectiveAnnotation { } } +/** A type whose values may be serialized using the Jackson JSON framework. */ abstract class JacksonSerializableType extends Type { } /** @@ -34,6 +38,7 @@ library class JacksonWriteValueMethod extends Method { } } +/** A type whose values are explicitly serialized in a call to a Jackson method. */ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType { ExplicitlyWrittenJacksonSerializableType() { exists(MethodAccess ma | @@ -45,12 +50,14 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab } } +/** A type used in a `JacksonSerializableField` declaration. */ library class FieldReferencedJacksonSerializableType extends JacksonSerializableType { FieldReferencedJacksonSerializableType() { exists(JacksonSerializableField f | usesType(f.getType(), this)) } } +/** A type whose values may be deserialized by the Jackson JSON framework. */ abstract class JacksonDeserializableType extends Type { } private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::Configuration { @@ -76,6 +83,7 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C TypeLiteral getSourceWithFlowToJacksonDatabind() { hasFlow(DataFlow::exprNode(result), _) } } +/** A type whose values are explicitly deserialized in a call to a Jackson method. */ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType { ExplicitlyReadJacksonDeserializableType() { exists(TypeLiteralToJacksonDatabindFlowConfiguration conf | @@ -84,12 +92,14 @@ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializa } } +/** A type used in a `JacksonDeserializableField` declaration. */ library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType { FieldReferencedJacksonDeSerializableType() { exists(JacksonDeserializableField f | usesType(f.getType(), this)) } } +/** A field that may be serialized using the Jackson JSON framework. */ class JacksonSerializableField extends SerializableField { JacksonSerializableField() { exists(JacksonSerializableType superType | @@ -101,6 +111,7 @@ class JacksonSerializableField extends SerializableField { } } +/** A field that may be deserialized using the Jackson JSON framework. */ class JacksonDeserializableField extends DeserializableField { JacksonDeserializableField() { exists(JacksonDeserializableType superType | @@ -183,6 +194,7 @@ class JacksonMixinType extends ClassOrInterface { } } +/** A callable used as a Jackson mixin callable. */ class JacksonMixedInCallable extends Callable { JacksonMixedInCallable() { exists(JacksonMixinType mixinType | this = mixinType.getAMixedInCallable()) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll b/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll index 707a930a06d..1d6c08c4862 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Java Server Faces. */ + import default import semmle.code.java.frameworks.javaee.jsf.JSFAnnotations import semmle.code.java.frameworks.javaee.jsf.JSFFacesContextXML @@ -42,6 +44,7 @@ class FacesAccessibleType extends RefType { ) } + /** Gets a method declared on this type that is visible to JSF. */ FacesVisibleMethod getAnAccessibleMethod() { result = getAMethod() } } diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll b/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll index 7236f939e88..e980cb2187a 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with the JavaEE Persistence API. + */ + import java /** @@ -29,7 +33,7 @@ class PersistentEntity extends RefType { } /** - * If there is an annotation on this class defining the access type, then this is the type. + * Gets the access type for this entity as defined by a `@javax.persistence.Access` annotation, if any. */ string getAccessTypeFromAnnotation() { exists(AccessAnnotation accessType | accessType = getAnAnnotation() | @@ -43,376 +47,607 @@ class PersistentEntity extends RefType { * Annotations in the `javax.persistence` package. */ +/** + * A `@javax.persistence.Access` annotation. + */ class AccessAnnotation extends Annotation { AccessAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Access") } } +/** + * A `@javax.persistence.AccessType` annotation. + */ class AccessTypeAnnotation extends Annotation { AccessTypeAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AccessType") } } +/** + * A `@javax.persistence.AssociationOverride` annotation. + */ class AssociationOverrideAnnotation extends Annotation { AssociationOverrideAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AssociationOverride") } } +/** + * A `@javax.persistence.AssociationOverrides` annotation. + */ class AssociationOverridesAnnotation extends Annotation { AssociationOverridesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AssociationOverrides") } } +/** + * A `@javax.persistence.AttributeOverride` annotation. + */ class AttributeOverrideAnnotation extends Annotation { AttributeOverrideAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AttributeOverride") } } +/** + * A `@javax.persistence.AttributeOverrides` annotation. + */ class AttributeOverridesAnnotation extends Annotation { AttributeOverridesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AttributeOverrides") } } +/** + * A `@javax.persistence.Basic` annotation. + */ class BasicAnnotation extends Annotation { BasicAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Basic") } } +/** + * A `@javax.persistence.Cacheable` annotation. + */ class CacheableAnnotation extends Annotation { CacheableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Cacheable") } } +/** + * A `@javax.persistence.CollectionTable` annotation. + */ class CollectionTableAnnotation extends Annotation { CollectionTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "CollectionTable") } } +/** + * A `@javax.persistence.Column` annotation. + */ class ColumnAnnotation extends Annotation { ColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Column") } } +/** + * A `@javax.persistence.ColumnResult` annotation. + */ class ColumnResultAnnotation extends Annotation { ColumnResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ColumnResult") } } +/** + * A `@javax.persistence.DiscriminatorColumn` annotation. + */ class DiscriminatorColumnAnnotation extends Annotation { DiscriminatorColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "DiscriminatorColumn") } } +/** + * A `@javax.persistence.DiscriminatorValue` annotation. + */ class DiscriminatorValueAnnotation extends Annotation { DiscriminatorValueAnnotation() { this.getType().hasQualifiedName("javax.persistence", "DiscriminatorValue") } } +/** + * A `@javax.persistence.ElementCollection` annotation. + */ class ElementCollectionAnnotation extends Annotation { ElementCollectionAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ElementCollection") } } +/** + * A `@javax.persistence.Embeddable` annotation. + */ class EmbeddableAnnotation extends Annotation { EmbeddableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Embeddable") } } +/** + * A `@javax.persistence.Embedded` annotation. + */ class EmbeddedAnnotation extends Annotation { EmbeddedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Embedded") } } +/** + * A `@javax.persistence.EmbeddedId` annotation. + */ class EmbeddedIdAnnotation extends Annotation { EmbeddedIdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EmbeddedId") } } +/** + * A `@javax.persistence.Entity` annotation. + */ class EntityAnnotation extends Annotation { EntityAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Entity") } } +/** + * A `@javax.persistence.EntityListeners` annotation. + */ class EntityListenersAnnotation extends Annotation { EntityListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EntityListeners") } } +/** + * A `@javax.persistence.EntityResult` annotation. + */ class EntityResultAnnotation extends Annotation { EntityResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EntityResult") } } +/** + * A `@javax.persistence.Enumerated` annotation. + */ class EnumeratedAnnotation extends Annotation { EnumeratedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Enumerated") } } +/** + * A `@javax.persistence.ExcludeDefaultListeners` annotation. + */ class ExcludeDefaultListenersAnnotation extends Annotation { ExcludeDefaultListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ExcludeDefaultListeners") } } +/** + * A `@javax.persistence.ExcludeSuperclassListeners` annotation. + */ class ExcludeSuperclassListenersAnnotation extends Annotation { ExcludeSuperclassListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ExcludeSuperclassListeners") } } +/** + * A `@javax.persistence.FieldResult` annotation. + */ class FieldResultAnnotation extends Annotation { FieldResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "FieldResult") } } +/** + * A `@javax.persistence.GeneratedValue` annotation. + */ class GeneratedValueAnnotation extends Annotation { GeneratedValueAnnotation() { this.getType().hasQualifiedName("javax.persistence", "GeneratedValue") } } +/** + * A `@javax.persistence.Id` annotation. + */ class IdAnnotation extends Annotation { IdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Id") } } +/** + * A `@javax.persistence.IdClass` annotation. + */ class IdClassAnnotation extends Annotation { IdClassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "IdClass") } } +/** + * A `@javax.persistence.Inheritance` annotation. + */ class InheritanceAnnotation extends Annotation { InheritanceAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Inheritance") } } +/** + * A `@javax.persistence.JoinColumn` annotation. + */ class JoinColumnAnnotation extends Annotation { JoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinColumn") } } +/** + * A `@javax.persistence.JoinColumns` annotation. + */ class JoinColumnsAnnotation extends Annotation { JoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinColumns") } } +/** + * A `@javax.persistence.JoinTable` annotation. + */ class JoinTableAnnotation extends Annotation { JoinTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinTable") } } +/** + * A `@javax.persistence.Lob` annotation. + */ class LobAnnotation extends Annotation { LobAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Lob") } } +/** + * A `@javax.persistence.ManyToMany` annotation. + */ class ManyToManyAnnotation extends Annotation { ManyToManyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ManyToMany") } } +/** + * A `@javax.persistence.ManyToOne` annotation. + */ class ManyToOneAnnotation extends Annotation { ManyToOneAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ManyToOne") } } +/** + * A `@javax.persistence.MapKey` annotation. + */ class MapKeyAnnotation extends Annotation { MapKeyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKey") } } +/** + * A `@javax.persistence.MapKeyClass` annotation. + */ class MapKeyClassAnnotation extends Annotation { MapKeyClassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyClass") } } +/** + * A `@javax.persistence.MapKeyColumn` annotation. + */ class MapKeyColumnAnnotation extends Annotation { MapKeyColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyColumn") } } +/** + * A `@javax.persistence.MapKeyEnumerated` annotation. + */ class MapKeyEnumeratedAnnotation extends Annotation { MapKeyEnumeratedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyEnumerated") } } +/** + * A `@javax.persistence.MapKeyJoinColumn` annotation. + */ class MapKeyJoinColumnAnnotation extends Annotation { MapKeyJoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyJoinColumn") } } +/** + * A `@javax.persistence.MapKeyJoinColumns` annotation. + */ class MapKeyJoinColumnsAnnotation extends Annotation { MapKeyJoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyJoinColumns") } } +/** + * A `@javax.persistence.MapKeyTemporal` annotation. + */ class MapKeyTemporalAnnotation extends Annotation { MapKeyTemporalAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyTemporal") } } +/** + * A `@javax.persistence.MappedSuperclass` annotation. + */ class MappedSuperclassAnnotation extends Annotation { MappedSuperclassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MappedSuperclass") } } +/** + * A `@javax.persistence.MapsId` annotation. + */ class MapsIdAnnotation extends Annotation { MapsIdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapsId") } } +/** + * A `@javax.persistence.NamedNativeQueries` annotation. + */ class NamedNativeQueriesAnnotation extends Annotation { NamedNativeQueriesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedNativeQueries") } } +/** + * A `@javax.persistence.NamedNativeQuery` annotation. + */ class NamedNativeQueryAnnotation extends Annotation { NamedNativeQueryAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedNativeQuery") } } +/** + * A `@javax.persistence.NamedQueries` annotation. + */ class NamedQueriesAnnotation extends Annotation { NamedQueriesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedQueries") } } +/** + * A `@javax.persistence.NamedQuery` annotation. + */ class NamedQueryAnnotation extends Annotation { NamedQueryAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedQuery") } } +/** + * A `@javax.persistence.OneToMany` annotation. + */ class OneToManyAnnotation extends Annotation { OneToManyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OneToMany") } } +/** + * A `@javax.persistence.OneToOne` annotation. + */ class OneToOneAnnotation extends Annotation { OneToOneAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OneToOne") } } +/** + * A `@javax.persistence.OrderBy` annotation. + */ class OrderByAnnotation extends Annotation { OrderByAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OrderBy") } } +/** + * A `@javax.persistence.OrderColumn` annotation. + */ class OrderColumnAnnotation extends Annotation { OrderColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OrderColumn") } } +/** + * A `@javax.persistence.PersistenceContext` annotation. + */ class PersistenceContextAnnotation extends Annotation { PersistenceContextAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceContext") } } +/** + * A `@javax.persistence.PersistenceContexts` annotation. + */ class PersistenceContextsAnnotation extends Annotation { PersistenceContextsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceContexts") } } +/** + * A `@javax.persistence.PersistenceProperty` annotation. + */ class PersistencePropertyAnnotation extends Annotation { PersistencePropertyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceProperty") } } +/** + * A `@javax.persistence.PersistenceUnit` annotation. + */ class PersistenceUnitAnnotation extends Annotation { PersistenceUnitAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceUnit") } } +/** + * A `@javax.persistence.PersistenceUnits` annotation. + */ class PersistenceUnitsAnnotation extends Annotation { PersistenceUnitsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceUnits") } } +/** + * A `@javax.persistence.PostLoad` annotation. + */ class PostLoadAnnotation extends Annotation { PostLoadAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostLoad") } } +/** + * A `@javax.persistence.PostPersist` annotation. + */ class PostPersistAnnotation extends Annotation { PostPersistAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostPersist") } } +/** + * A `@javax.persistence.PostRemove` annotation. + */ class PostRemoveAnnotation extends Annotation { PostRemoveAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostRemove") } } +/** + * A `@javax.persistence.PostUpdate` annotation. + */ class PostUpdateAnnotation extends Annotation { PostUpdateAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostUpdate") } } +/** + * A `@javax.persistence.PrePersist` annotation. + */ class PrePersistAnnotation extends Annotation { PrePersistAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrePersist") } } +/** + * A `@javax.persistence.PreRemove` annotation. + */ class PreRemoveAnnotation extends Annotation { PreRemoveAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PreRemove") } } +/** + * A `@javax.persistence.PreUpdate` annotation. + */ class PreUpdateAnnotation extends Annotation { PreUpdateAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PreUpdate") } } +/** + * A `@javax.persistence.PrimaryKeyJoinColumn` annotation. + */ class PrimaryKeyJoinColumnAnnotation extends Annotation { PrimaryKeyJoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrimaryKeyJoinColumn") } } +/** + * A `@javax.persistence.PrimaryKeyJoinColumns` annotation. + */ class PrimaryKeyJoinColumnsAnnotation extends Annotation { PrimaryKeyJoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrimaryKeyJoinColumns") } } +/** + * A `@javax.persistence.QueryHint` annotation. + */ class QueryHintAnnotation extends Annotation { QueryHintAnnotation() { this.getType().hasQualifiedName("javax.persistence", "QueryHint") } } +/** + * A `@javax.persistence.SecondaryTable` annotation. + */ class SecondaryTableAnnotation extends Annotation { SecondaryTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SecondaryTable") } } +/** + * A `@javax.persistence.SecondaryTables` annotation. + */ class SecondaryTablesAnnotation extends Annotation { SecondaryTablesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SecondaryTables") } } +/** + * A `@javax.persistence.SequenceGenerator` annotation. + */ class SequenceGeneratorAnnotation extends Annotation { SequenceGeneratorAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SequenceGenerator") } } +/** + * A `@javax.persistence.SqlResultSetMapping` annotation. + */ class SqlResultSetMappingAnnotation extends Annotation { SqlResultSetMappingAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SqlResultSetMapping") } } +/** + * A `@javax.persistence.SqlResultSetMappings` annotation. + */ class SqlResultSetMappingsAnnotation extends Annotation { SqlResultSetMappingsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SqlResultSetMappings") } } +/** + * A `@javax.persistence.Table` annotation. + */ class TableAnnotation extends Annotation { TableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Table") } } +/** + * A `@javax.persistence.TableGenerator` annotation. + */ class TableGeneratorAnnotation extends Annotation { TableGeneratorAnnotation() { this.getType().hasQualifiedName("javax.persistence", "TableGenerator") } } +/** + * A `@javax.persistence.Temporal` annotation. + */ class TemporalAnnotation extends Annotation { TemporalAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Temporal") } } +/** + * A `@javax.persistence.Transient` annotation. + */ class TransientAnnotation extends Annotation { TransientAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Transient") } } +/** + * A `@javax.persistence.UniqueConstraint` annotation. + */ class UniqueConstraintAnnotation extends Annotation { UniqueConstraintAnnotation() { this.getType().hasQualifiedName("javax.persistence", "UniqueConstraint") } } +/** + * A `@javax.persistence.Version` annotation. + */ class VersionAnnotation extends Annotation { VersionAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Version") } } diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll b/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll index fdb0ce30431..8051b470bd3 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for working with JavaEE + * persistence configuration XML files (`persistence.xml`). + */ + import java /** @@ -6,66 +11,94 @@ import java class PersistenceXMLFile extends XMLFile { PersistenceXMLFile() { this.getStem() = "persistence" } + /** Gets the root XML element in this `persistence.xml` file. */ PersistenceXmlRoot getRoot() { result = this.getAChild() } - // convenience methods + /** Gets a `shared-cache-mode` XML element nested within this `persistence.xml` file. */ SharedCacheModeElement getASharedCacheModeElement() { result = this.getRoot().getAPersistenceUnitElement().getASharedCacheModeElement() } + /** Gets a `property` XML element nested within this `persistence.xml` file. */ PersistencePropertyElement getAPropertyElement() { result = this.getRoot().getAPersistenceUnitElement().getAPropertiesElement().getAPropertyElement() } } +/** The root `persistence` XML element in a `persistence.xml` file. */ class PersistenceXmlRoot extends XMLElement { PersistenceXmlRoot() { this.getParent() instanceof PersistenceXMLFile and this.getName() = "persistence" } + /** Gets a `persistence-unit` child XML element of this `persistence` XML element. */ PersistenceUnitElement getAPersistenceUnitElement() { result = this.getAChild() } } +/** + * A `persistence-unit` child XML element of the root + * `persistence` XML element in a `persistence.xml` file. + */ class PersistenceUnitElement extends XMLElement { PersistenceUnitElement() { this.getParent() instanceof PersistenceXmlRoot and this.getName() = "persistence-unit" } + /** Gets a `shared-cache-mode` child XML element of this `persistence-unit` XML element. */ SharedCacheModeElement getASharedCacheModeElement() { result = this.getAChild() } + /** Gets a `properties` child XML element of this `persistence-unit` XML element. */ PersistencePropertiesElement getAPropertiesElement() { result = this.getAChild() } } +/** + * A `shared-cache-mode` child XML element of a `persistence-unit` + * XML element in a `persistence.xml` file. + */ class SharedCacheModeElement extends XMLElement { SharedCacheModeElement() { this.getParent() instanceof PersistenceUnitElement and this.getName() = "shared-cache-mode" } + /** Gets the value of this `shared-cache-mode` XML element. */ string getValue() { result = this.getACharactersSet().getCharacters() } + /** Holds if this `shared-cache-mode` XML element has the value "NONE". */ predicate isDisabled() { this.getValue() = "NONE" } } +/** + * A `properties` child XML element of a `persistence-unit` + * XML element in a `persistence.xml` file. + */ class PersistencePropertiesElement extends XMLElement { PersistencePropertiesElement() { this.getParent() instanceof PersistenceUnitElement and this.getName() = "properties" } + /** Gets a `property` child XML element of this `properties` XML element. */ PersistencePropertyElement getAPropertyElement() { result = this.getAChild() } } +/** + * A `property` child XML element of a `properties` + * XML element in a `persistence.xml` file. + */ class PersistencePropertyElement extends XMLElement { PersistencePropertyElement() { this.getParent() instanceof PersistencePropertiesElement and this.getName() = "property" } - /** see http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching */ + /** + * Holds if this `property` XML element of a `persistence.xml` file + * disables the EclipseLink shared cache. + */ predicate disablesEclipseLinkSharedCache() { getAttribute("name").getValue() = "eclipselink.cache.shared.default" and getAttribute("value").getValue() = "false" diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll index 2a9cf547739..6afcf78272f 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Enterprise Java Beans. */ + import java import EJBJarXML @@ -322,10 +324,17 @@ class LocalAnnotatedBusinessInterface extends AnnotatedBusinessInterface { * Init and create methods for session beans. */ +/** + * A `@javax.ejb.Init` annotation. + */ class InitAnnotation extends Annotation { InitAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Init") } } +/** + * A method annotated with a `@javax.ejb.Init` annotation + * that is declared in or inherited by a session EJB. + */ class EjbAnnotatedInitMethod extends Method { EjbAnnotatedInitMethod() { this.getAnAnnotation() instanceof InitAnnotation and @@ -333,21 +342,31 @@ class EjbAnnotatedInitMethod extends Method { } } +/** + * A method whose name starts with `ejbCreate` that is + * declared in or inherited by a session EJB. + */ class EjbCreateMethod extends Method { EjbCreateMethod() { this.getName().matches("ejbCreate%") and exists(SessionEJB ejb | ejb.inherits(this)) } + /** Gets the suffix of the method name without the `ejbCreate` prefix. */ string getMethodSuffix() { result = this.getName().substring(9, this.getName().length()) } } +/** + * A method whose name starts with `create` that is + * declared in or inherited by a legacy EJB home interface. + */ class EjbInterfaceCreateMethod extends Method { EjbInterfaceCreateMethod() { this.getName().matches("create%") and exists(LegacyEjbHomeInterface i | i.inherits(this)) } + /** Gets the suffix of the method name without the `create` prefix. */ string getMethodSuffix() { result = this.getName().substring(6, this.getName().length()) } } @@ -398,6 +417,10 @@ class XmlSpecifiedRemoteInterface extends LegacyEjbRemoteInterface { ) } + /** + * Gets a session EJB specified in the XML deployment descriptor + * for this legacy EJB remote interface. + */ SessionEJB getAnEJB() { exists(EjbJarXMLFile f, EjbJarSessionElement se | se = f.getASessionElement() and @@ -423,6 +446,7 @@ class AnnotatedRemoteHomeInterface extends LegacyEjbRemoteHomeInterface { /** Gets an EJB to which this interface belongs. */ SessionEJB getAnEJB() { result.getAnAnnotation().(RemoteHomeAnnotation).getANamedType() = this } + /** Gets a remote interface associated with this legacy remote home interface. */ Interface getAnAssociatedRemoteInterface() { result = getACreateMethod().getReturnType() } } @@ -486,6 +510,7 @@ class AnnotatedLocalHomeInterface extends LegacyEjbLocalHomeInterface { /** Gets an EJB to which this interface belongs. */ SessionEJB getAnEJB() { result.getAnAnnotation().(LocalHomeAnnotation).getANamedType() = this } + /** Gets a local interface associated with this legacy local home interface. */ Interface getAnAssociatedLocalInterface() { result = getACreateMethod().getReturnType() } } @@ -535,6 +560,7 @@ class RemoteInterface extends Interface { */ Method getARemoteMethod() { this.inherits(result) } + /** Gets a remote method implementation for this remote interface. */ Method getARemoteMethodImplementation() { result = getARemoteMethodImplementationChecked() or result = getARemoteMethodImplementationUnchecked() @@ -716,127 +742,209 @@ Type inheritsMatchingCreateMethodExceptThrows(StatefulSessionEJB ejb, EjbInterfa * Annotations in the `javax.ejb package`. */ +/** + * A `@javax.ejb.AccessTimeout` annotation. + */ class AccessTimeoutAnnotation extends Annotation { AccessTimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AccessTimeout") } } +/** + * A `@javax.ejb.ActivationConfigProperty` annotation. + */ class ActivationConfigPropertyAnnotation extends Annotation { ActivationConfigPropertyAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ActivationConfigProperty") } } +/** + * A `@javax.ejb.AfterBegin` annotation. + */ class AfterBeginAnnotation extends Annotation { AfterBeginAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AfterBegin") } } +/** + * A `@javax.ejb.AfterCompletion` annotation. + */ class AfterCompletionAnnotation extends Annotation { AfterCompletionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AfterCompletion") } } +/** + * A `@javax.ejb.ApplicationException` annotation. + */ class ApplicationExceptionAnnotation extends Annotation { ApplicationExceptionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ApplicationException") } } +/** + * A `@javax.ejb.Asynchronous` annotation. + */ class AsynchronousAnnotation extends Annotation { AsynchronousAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Asynchronous") } } +/** + * A `@javax.ejb.BeforeCompletion` annotation. + */ class BeforeCompletionAnnotation extends Annotation { BeforeCompletionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "BeforeCompletion") } } +/** + * A `@javax.ejb.ConcurrencyManagement` annotation. + */ class ConcurrencyManagementAnnotation extends Annotation { ConcurrencyManagementAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ConcurrencyManagement") } } +/** + * A `@javax.ejb.DependsOn` annotation. + */ class DependsOnAnnotation extends Annotation { DependsOnAnnotation() { this.getType().hasQualifiedName("javax.ejb", "DependsOn") } } +/** + * A `@javax.ejb.EJB` annotation. + */ class EJBAnnotation extends Annotation { EJBAnnotation() { this.getType().hasQualifiedName("javax.ejb", "EJB") } } +/** + * A `@javax.ejb.EJBs` annotation. + */ class EJBsAnnotation extends Annotation { EJBsAnnotation() { this.getType().hasQualifiedName("javax.ejb", "EJBs") } } -// See above for `@Init`, `@Local`. +/** + * A `@javax.ejb.LocalBean` annotation. + */ class LocalBeanAnnotation extends Annotation { LocalBeanAnnotation() { this.getType().hasQualifiedName("javax.ejb", "LocalBean") } } -// See above for `@LocalHome`. +/** + * A `@javax.ejb.Lock` annotation. + */ class LockAnnotation extends Annotation { LockAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Lock") } } +/** + * A `@javax.ejb.MessageDriven` annotation. + */ class MessageDrivenAnnotation extends Annotation { MessageDrivenAnnotation() { this.getType().hasQualifiedName("javax.ejb", "MessageDriven") } } +/** + * A `@javax.ejb.PostActivate` annotation. + */ class PostActivateAnnotation extends Annotation { PostActivateAnnotation() { this.getType().hasQualifiedName("javax.ejb", "PostActivate") } } +/** + * A `@javax.ejb.PrePassivate` annotation. + */ class PrePassivateAnnotation extends Annotation { PrePassivateAnnotation() { this.getType().hasQualifiedName("javax.ejb", "PrePassivate") } } -// See above for `@Remote`, `@RemoteHome`. +/** + * A `@javax.ejb.Remove` annotation. + */ class RemoveAnnotation extends Annotation { RemoveAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Remove") } } +/** + * A `@javax.ejb.Schedule` annotation. + */ class ScheduleAnnotation extends Annotation { ScheduleAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Schedule") } } +/** + * A `@javax.ejb.Schedules` annotation. + */ class SchedulesAnnotation extends Annotation { SchedulesAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Schedules") } } +/** + * A `@javax.ejb.Singleton` annotation. + */ class SingletonAnnotation extends Annotation { SingletonAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Singleton") } } +/** + * A `@javax.ejb.Startup` annotation. + */ class StartupAnnotation extends Annotation { StartupAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Startup") } } +/** + * A `@javax.ejb.Stateful` annotation. + */ class StatefulAnnotation extends Annotation { StatefulAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Stateful") } } +/** + * A `@javax.ejb.StatefulTimeout` annotation. + */ class StatefulTimeoutAnnotation extends Annotation { StatefulTimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "StatefulTimeout") } } +/** + * A `@javax.ejb.Stateless` annotation. + */ class StatelessAnnotation extends Annotation { StatelessAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Stateless") } } +/** + * A `@javax.ejb.Timeout` annotation. + */ class TimeoutAnnotation extends Annotation { TimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Timeout") } } +/** + * A `@javax.ejb.TransactionAttribute` annotation. + */ class TransactionAttributeAnnotation extends Annotation { TransactionAttributeAnnotation() { this.getType().hasQualifiedName("javax.ejb", "TransactionAttribute") } } +/** + * A `@javax.ejb.TransactionManagement` annotation. + */ class TransactionManagementAnnotation extends Annotation { TransactionManagementAnnotation() { this.getType().hasQualifiedName("javax.ejb", "TransactionManagement") } } +/** + * A `@javax.ejb.TransactionAttribute` annotation with the + * transaction attribute type set to `REQUIRED`. + */ class RequiredTransactionAttributeAnnotation extends TransactionAttributeAnnotation { RequiredTransactionAttributeAnnotation() { exists(FieldRead fr | @@ -847,6 +955,10 @@ class RequiredTransactionAttributeAnnotation extends TransactionAttributeAnnotat } } +/** + * A `@javax.ejb.TransactionAttribute` annotation with the + * transaction attribute type set to `REQUIRES_NEW`. + */ class RequiresNewTransactionAttributeAnnotation extends TransactionAttributeAnnotation { RequiresNewTransactionAttributeAnnotation() { exists(FieldRead fr | @@ -861,6 +973,9 @@ class RequiresNewTransactionAttributeAnnotation extends TransactionAttributeAnno * Convenience methods. */ +/** + * Gets the innermost `@javax.ejb.TransactionAttribute` annotation for method `m`. + */ TransactionAttributeAnnotation getInnermostTransactionAttributeAnnotation(Method m) { // A `TransactionAttribute` annotation can either be on the method itself, // in which case it supersedes any such annotation on the declaring class... @@ -876,6 +991,10 @@ TransactionAttributeAnnotation getInnermostTransactionAttributeAnnotation(Method * Methods in the `javax.ejb package`. */ +/** + * A method named `setRollbackOnly` declared on the + * interface `javax.ejb.EJBContext` or a subtype thereof. + */ class SetRollbackOnlyMethod extends Method { SetRollbackOnlyMethod() { this.getDeclaringType().getASupertype*().hasQualifiedName("javax.ejb", "EJBContext") and diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll index bc92178e06e..02e73c2be5c 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for working with + * EJB deployment descriptor XML files (`ejb-jar.xml`). + */ + import java /** @@ -6,161 +11,222 @@ import java class EjbJarXMLFile extends XMLFile { EjbJarXMLFile() { this.getStem() = "ejb-jar" } + /** Gets the root `ejb-jar` XML element of this `ejb-jar.xml` file. */ EjbJarRootElement getRoot() { result = this.getAChild() } - // Convenience methods. + /** Gets an `enterprise-beans` XML element nested within this `ejb-jar.xml` file. */ EjbJarEnterpriseBeansElement getAnEnterpriseBeansElement() { result = this.getRoot().getAnEnterpriseBeansElement() } + /** Gets a `session` XML element nested within this `ejb-jar.xml` file. */ EjbJarSessionElement getASessionElement() { result = this.getAnEnterpriseBeansElement().getASessionElement() } + /** Gets a `message-driven` XML element nested within this `ejb-jar.xml` file. */ EjbJarMessageDrivenElement getAMessageDrivenElement() { result = this.getAnEnterpriseBeansElement().getAMessageDrivenElement() } + /** Gets an `entity` XML element nested within this `ejb-jar.xml` file. */ EjbJarEntityElement getAnEntityElement() { result = this.getAnEnterpriseBeansElement().getAnEntityElement() } } +/** The root `ejb-jar` XML element in an `ejb-jar.xml` file. */ class EjbJarRootElement extends XMLElement { EjbJarRootElement() { this.getParent() instanceof EjbJarXMLFile and this.getName() = "ejb-jar" } + /** Gets an `enterprise-beans` child XML element of this root `ejb-jar` XML element. */ EjbJarEnterpriseBeansElement getAnEnterpriseBeansElement() { result = this.getAChild() } } +/** + * An `enterprise-beans` child XML element of the root + * `ejb-jar` XML element in an `ejb-jar.xml` file. + */ class EjbJarEnterpriseBeansElement extends XMLElement { EjbJarEnterpriseBeansElement() { this.getParent() instanceof EjbJarRootElement and this.getName() = "enterprise-beans" } + /** Gets a `session` child XML element of this `enterprise-beans` XML element. */ EjbJarSessionElement getASessionElement() { result = this.getAChild() and result.getName() = "session" } + /** Gets a `message-driven` child XML element of this `enterprise-beans` XML element. */ EjbJarMessageDrivenElement getAMessageDrivenElement() { result = this.getAChild() and result.getName() = "message-driven" } + /** Gets an `entity` child XML element of this `enterprise-beans` XML element. */ EjbJarEntityElement getAnEntityElement() { result = this.getAChild() and result.getName() = "entity" } } +/** + * A child XML element of an `enterprise-beans` XML element within an `ejb-jar.xml` file. + * + * This is either a `message-driven` element, a `session` element, or an `entity` element. + */ abstract class EjbJarBeanTypeElement extends XMLElement { EjbJarBeanTypeElement() { this.getParent() instanceof EjbJarEnterpriseBeansElement } + /** Gets an `ejb-class` child XML element of this bean type element. */ XMLElement getAnEjbClassElement() { result = this.getAChild() and result.getName() = "ejb-class" } } +/** + * A `session` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarSessionElement extends EjbJarBeanTypeElement { EjbJarSessionElement() { this.getName() = "session" } + /** Gets a `business-local` child XML element of this `session` XML element. */ XMLElement getABusinessLocalElement() { result = this.getAChild() and result.getName() = "business-local" } + /** Gets a `business-remote` child XML element of this `session` XML element. */ XMLElement getABusinessRemoteElement() { result = this.getAChild() and result.getName() = "business-remote" } + /** + * Gets a business child XML element of this `session` XML element. + * + * This is either a `business-local` or `business-remote` element. + */ XMLElement getABusinessElement() { result = getABusinessLocalElement() or result = getABusinessRemoteElement() } + /** Gets a `remote` child XML element of this `session` XML element. */ XMLElement getARemoteElement() { result = this.getAChild() and result.getName() = "remote" } + /** Gets a `home` child XML element of this `session` XML element. */ XMLElement getARemoteHomeElement() { result = this.getAChild() and result.getName() = "home" } + /** Gets a `local` child XML element of this `session` XML element. */ XMLElement getALocalElement() { result = this.getAChild() and result.getName() = "local" } + /** Gets a `local-home` child XML element of this `session` XML element. */ XMLElement getALocalHomeElement() { result = this.getAChild() and result.getName() = "local-home" } + /** Gets a `session-type` child XML element of this `session` XML element. */ EjbJarSessionTypeElement getASessionTypeElement() { result = this.getAChild() } + /** Gets an `init-method` child XML element of this `session` XML element. */ EjbJarInitMethodElement getAnInitMethodElement() { result = this.getAChild() } - // Convenience methods. + /** + * Gets a `method-name` child XML element of a `create-method` + * XML element nested within this `session` XML element. + */ XMLElement getACreateMethodNameElement() { result = getAnInitMethodElement().getACreateMethodElement().getAMethodNameElement() } + /** + * Gets a `method-name` child XML element of a `bean-method` + * XML element nested within this `session` XML element. + */ XMLElement getABeanMethodNameElement() { result = getAnInitMethodElement().getABeanMethodElement().getAMethodNameElement() } } +/** + * A `message-driven` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarMessageDrivenElement extends EjbJarBeanTypeElement { EjbJarMessageDrivenElement() { this.getName() = "message-driven" } } +/** + * An `entity` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarEntityElement extends EjbJarBeanTypeElement { EjbJarEntityElement() { this.getName() = "entity" } } +/** A `session-type` child XML element of a `session` element in an `ejb-jar.xml` file. */ class EjbJarSessionTypeElement extends XMLElement { EjbJarSessionTypeElement() { this.getParent() instanceof EjbJarSessionElement and this.getName() = "session-type" } + /** Holds if the value of this `session-type` XML element is "Stateful". */ predicate isStateful() { this.getACharactersSet().getCharacters() = "Stateful" } + /** Holds if the value of this `session-type` XML element is "Stateless". */ predicate isStateless() { this.getACharactersSet().getCharacters() = "Stateless" } } +/** An `init-method` child XML element of a `session` element in an `ejb-jar.xml` file. */ class EjbJarInitMethodElement extends XMLElement { EjbJarInitMethodElement() { this.getParent() instanceof EjbJarSessionElement and this.getName() = "init-method" } + /** Gets a `create-method` child XML element of this `init-method` XML element. */ EjbJarCreateMethodElement getACreateMethodElement() { result = this.getAChild() and result.getName() = "create-method" } + /** Gets a `bean-method` child XML element of this `init-method` XML element. */ EjbJarBeanMethodElement getABeanMethodElement() { result = this.getAChild() and result.getName() = "bean-method" } } +/** + * A child XML element of an `init-method` element in an `ejb-jar.xml` file. + * + * This is either a `create-method` element, or a `bean-method` element. + */ abstract class EjbJarInitMethodChildElement extends XMLElement { + /** Gets a `method-name` child XML element of this `create-method` or `bean-method` XML element. */ XMLElement getAMethodNameElement() { result = this.getAChild() and result.getName() = "method-name" } } +/** A `create-method` child XML element of an `init-method` element in an `ejb-jar.xml` file. */ class EjbJarCreateMethodElement extends EjbJarInitMethodChildElement { EjbJarCreateMethodElement() { this.getParent() instanceof EjbJarInitMethodElement and @@ -168,6 +234,7 @@ class EjbJarCreateMethodElement extends EjbJarInitMethodChildElement { } } +/** A `bean-method` child XML element of an `init-method` element in an `ejb-jar.xml` file. */ class EjbJarBeanMethodElement extends EjbJarInitMethodChildElement { EjbJarBeanMethodElement() { this.getParent() instanceof EjbJarInitMethodElement and diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll index 3d34ff50c7a..4d6693a4905 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll @@ -1,10 +1,12 @@ -import java -import EJB - -/* +/** + * Provides classes and predicates for modeling * EJB Programming Restrictions (see EJB 3.0 specification, section 21.1.2). */ +import java +import EJB + +/** A method or constructor that may not be called from an EJB. */ abstract class ForbiddenCallable extends Callable { } /** @@ -47,6 +49,7 @@ predicate ejbCalls(Callable origin, ForbiddenCallable target, Call call) { * Specification of "forbidden callables". */ +/** A method or constructor that may not be called by an EJB due to container interference. */ class ForbiddenContainerInterferenceCallable extends ForbiddenCallable { ForbiddenContainerInterferenceCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ClassLoaderClass or @@ -55,18 +58,21 @@ class ForbiddenContainerInterferenceCallable extends ForbiddenCallable { } } +/** A method or constructor involving file input or output that may not be called by an EJB. */ class ForbiddenFileCallable extends ForbiddenCallable { ForbiddenFileCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof FileInputOutputClass } } +/** A method or constructor involving graphics operations that may not be called by an EJB. */ class ForbiddenGraphicsCallable extends ForbiddenCallable { ForbiddenGraphicsCallable() { this.getDeclaringType().getASupertype*().getPackage() instanceof GraphicsPackage } } +/** A method or constructor involving native code that may not be called by an EJB. */ class ForbiddenNativeCallable extends ForbiddenCallable { ForbiddenNativeCallable() { this.isNative() or @@ -74,32 +80,38 @@ class ForbiddenNativeCallable extends ForbiddenCallable { } } +/** A method or constructor involving reflection that may not be called by and EJB. */ class ForbiddenReflectionCallable extends ForbiddenCallable { ForbiddenReflectionCallable() { this.getDeclaringType().getASupertype*().getPackage() instanceof ReflectionPackage } } +/** A method or constructor involving security configuration that may not be called by an EJB. */ class ForbiddenSecurityConfigurationCallable extends ForbiddenCallable { ForbiddenSecurityConfigurationCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof SecurityConfigClass } } +/** A method or constructor involving serialization that may not be called by an EJB. */ class ForbiddenSerializationCallable extends ForbiddenCallable { ForbiddenSerializationCallable() { this instanceof ForbiddenSerializationMethod } } +/** A method or constructor involving network factory operations that may not be called by an EJB. */ class ForbiddenSetFactoryCallable extends ForbiddenCallable { ForbiddenSetFactoryCallable() { this instanceof ForbiddenSetFactoryMethod } } +/** A method or constructor involving server socket operations that may not be called by an EJB. */ class ForbiddenServerSocketCallable extends ForbiddenCallable { ForbiddenServerSocketCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ServerSocketsClass } } +/** A method or constructor involving synchronization that may not be called by an EJB. */ class ForbiddenSynchronizationCallable extends ForbiddenCallable { ForbiddenSynchronizationCallable() { this.isSynchronized() @@ -112,26 +124,37 @@ class ForbiddenSynchronizationCallable extends ForbiddenCallable { } } +/** A method or constructor involving static field access that may not be called by an EJB. */ class ForbiddenStaticFieldCallable extends ForbiddenCallable { ForbiddenStaticFieldCallable() { exists(forbiddenStaticFieldUse(this)) } } +/** + * Gets an access to a non-final static field in callable `c` + * that is disallowed by the EJB specification. + */ FieldAccess forbiddenStaticFieldUse(Callable c) { result.getEnclosingCallable() = c and result.getField().isStatic() and not result.getField().isFinal() } +/** A method or constructor involving thread operations that may not be called by an EJB. */ class ForbiddenThreadingCallable extends ForbiddenCallable { ForbiddenThreadingCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ThreadingClass } } +/** A method or constructor referencing `this` that may not be called by an EJB. */ class ForbiddenThisCallable extends ForbiddenCallable { ForbiddenThisCallable() { exists(forbiddenThisUse(this)) } } +/** + * Gets an access to `this` in callable `c` + * that is disallowed by the EJB specification. + */ ThisAccess forbiddenThisUse(Callable c) { result.getEnclosingCallable() = c and ( @@ -144,6 +167,7 @@ ThisAccess forbiddenThisUse(Callable c) { * Specification of "forbidden packages". */ +/** The package `java.lang.reflect` or a subpackage thereof. */ class ReflectionPackage extends Package { ReflectionPackage() { this.getName() = "java.lang.reflect" or @@ -151,6 +175,7 @@ class ReflectionPackage extends Package { } } +/** The package `java.awt` or `javax.swing` or a subpackage thereof. */ class GraphicsPackage extends Package { GraphicsPackage() { this.getName() = "java.awt" or @@ -160,6 +185,7 @@ class GraphicsPackage extends Package { } } +/** The package `java.util.concurrent` or a subpackage thereof. */ class ConcurrentPackage extends Package { ConcurrentPackage() { this.getName() = "java.util.concurrent" or @@ -171,6 +197,7 @@ class ConcurrentPackage extends Package { * Specification of "forbidden classes". */ +/** The class `java.lang.Thread` or `java.lang.ThreadGroup`. */ class ThreadingClass extends Class { ThreadingClass() { this.hasQualifiedName("java.lang", "Thread") or @@ -178,6 +205,10 @@ class ThreadingClass extends Class { } } +/** + * The class `java.net.ServerSocket`, `java.net.MulticastSocket` + * or `java.nio.channels.ServerSocketChannel`. + */ class ServerSocketsClass extends Class { ServerSocketsClass() { this.hasQualifiedName("java.net", "ServerSocket") or @@ -186,6 +217,10 @@ class ServerSocketsClass extends Class { } } +/** + * A class in the package `java.security` named `Policy`, + * `Security`, `Provider`, `Signer` or `Identity`. + */ class SecurityConfigClass extends Class { SecurityConfigClass() { this.hasQualifiedName("java.security", "Policy") or @@ -196,14 +231,17 @@ class SecurityConfigClass extends Class { } } +/** The class `java.lang.ClassLoader`. */ class ClassLoaderClass extends Class { ClassLoaderClass() { this.hasQualifiedName("java.lang", "ClassLoader") } } +/** The class `java.lang.SecurityManager`. */ class SecurityManagerClass extends Class { SecurityManagerClass() { this.hasQualifiedName("java.lang", "SecurityManager") } } +/** A class involving file input or output. */ class FileInputOutputClass extends Class { FileInputOutputClass() { this.hasQualifiedName("java.io", "File") or @@ -222,7 +260,7 @@ class FileInputOutputClass extends Class { * Specification of "forbidden methods". */ -// Forbidden container interference. +/** A method that may cause EJB container interference. */ class ForbiddenContainerInterferenceMethod extends Method { ForbiddenContainerInterferenceMethod() { this instanceof SystemExitMethod or @@ -236,6 +274,10 @@ class ForbiddenContainerInterferenceMethod extends Method { } } +/** + * A method named `exit` declared in + * the class `java.lang.System`. + */ class SystemExitMethod extends Method { SystemExitMethod() { this.hasName("exit") and @@ -249,6 +291,10 @@ class SystemExitMethod extends Method { } } +/** + * A method named `exit` or `halt` declared in + * the class `java.lang.Runtime` or a subclass thereof. + */ class RuntimeExitOrHaltMethod extends Method { RuntimeExitOrHaltMethod() { (this.hasName("exit") or this.hasName("halt")) and @@ -262,6 +308,10 @@ class RuntimeExitOrHaltMethod extends Method { } } +/** + * A method named `addShutdownHook` or `removeShutdownHook` declared in + * the class `java.lang.Runtime` or a subclass thereof. + */ class RuntimeAddOrRemoveShutdownHookMethod extends Method { RuntimeAddOrRemoveShutdownHookMethod() { (this.hasName("addShutdownHook") or this.hasName("removeShutdownHook")) and @@ -275,6 +325,10 @@ class RuntimeAddOrRemoveShutdownHookMethod extends Method { } } +/** + * A method named `setErr` or `setOut` declared in + * the class `java.lang.System`. + */ class SystemSetPrintStreamMethod extends Method { SystemSetPrintStreamMethod() { (this.hasName("setErr") or this.hasName("setOut")) and @@ -288,6 +342,10 @@ class SystemSetPrintStreamMethod extends Method { } } +/** + * A method named `setIn` declared in + * the class `java.lang.System`. + */ class SystemSetInputStreamMethod extends Method { SystemSetInputStreamMethod() { this.hasName("setIn") and @@ -301,6 +359,10 @@ class SystemSetInputStreamMethod extends Method { } } +/** + * A method named `getSecurityManager` declared in + * the class `java.lang.System`. + */ class SystemGetSecurityManagerMethod extends Method { SystemGetSecurityManagerMethod() { this.hasName("getSecurityManager") and @@ -313,6 +375,10 @@ class SystemGetSecurityManagerMethod extends Method { } } +/** + * A method named `setSecurityManager` declared in + * the class `java.lang.System`. + */ class SystemSetSecurityManagerMethod extends Method { SystemSetSecurityManagerMethod() { this.hasName("setSecurityManager") and @@ -326,6 +392,10 @@ class SystemSetSecurityManagerMethod extends Method { } } +/** + * A method named `inheritedChannel` declared in + * the class `java.lang.System`. + */ class SystemInheritedChannelMethod extends Method { SystemInheritedChannelMethod() { this.hasName("inheritedChannel") and @@ -338,7 +408,7 @@ class SystemInheritedChannelMethod extends Method { } } -// Forbidden serialization. +/** A method involving serialization that may not be called from an EJB. */ class ForbiddenSerializationMethod extends Method { ForbiddenSerializationMethod() { this instanceof EnableReplaceObjectMethod or @@ -350,6 +420,10 @@ class ForbiddenSerializationMethod extends Method { } } +/** + * A method named `enableReplaceObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class EnableReplaceObjectMethod extends Method { EnableReplaceObjectMethod() { this.hasName("enableReplaceObject") and @@ -363,6 +437,10 @@ class EnableReplaceObjectMethod extends Method { } } +/** + * A method named `replaceObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ReplaceObjectMethod extends Method { ReplaceObjectMethod() { this.hasName("replaceObject") and @@ -376,6 +454,10 @@ class ReplaceObjectMethod extends Method { } } +/** + * A method named `enableResolveObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class EnableResolveObjectMethod extends Method { EnableResolveObjectMethod() { this.hasName("enableResolveObject") and @@ -389,6 +471,10 @@ class EnableResolveObjectMethod extends Method { } } +/** + * A method named `resolveObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveObjectMethod extends Method { ResolveObjectMethod() { this.hasName("resolveObject") and @@ -402,6 +488,10 @@ class ResolveObjectMethod extends Method { } } +/** + * A method named `resolveClass` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveClassMethod extends Method { ResolveClassMethod() { this.hasName("resolveClass") and @@ -415,6 +505,10 @@ class ResolveClassMethod extends Method { } } +/** + * A method named `resolveProxyClass` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveProxyClassMethod extends Method { ResolveProxyClassMethod() { this.hasName("resolveProxyClass") and @@ -434,7 +528,7 @@ class ResolveProxyClassMethod extends Method { } } -// Forbidden "set factory" methods. +/** A method involving network factory operations that may not be called from an EJB. */ class ForbiddenSetFactoryMethod extends Method { ForbiddenSetFactoryMethod() { this instanceof SetSocketFactoryMethod or @@ -443,6 +537,10 @@ class ForbiddenSetFactoryMethod extends Method { } } +/** + * A method named `setSocketFactory` declared in + * the class `java.net.ServerSocket` or a subclass thereof. + */ class SetSocketFactoryMethod extends Method { SetSocketFactoryMethod() { this.hasName("setSocketFactory") and @@ -461,6 +559,10 @@ class SetSocketFactoryMethod extends Method { } } +/** + * A method named `setSocketImplFactory` declared in + * the class `java.net.Socket` or a subclass thereof. + */ class SetSocketImplFactoryMethod extends Method { SetSocketImplFactoryMethod() { this.hasName("setSocketImplFactory") and @@ -479,6 +581,10 @@ class SetSocketImplFactoryMethod extends Method { } } +/** + * A method named `setURLStreamHandlerFactory` declared in + * the class `java.net.URL` or a subclass thereof. + */ class SetUrlStreamHandlerFactoryMethod extends Method { SetUrlStreamHandlerFactoryMethod() { this.hasName("setURLStreamHandlerFactory") and @@ -497,7 +603,7 @@ class SetUrlStreamHandlerFactoryMethod extends Method { } } -// Forbidden native code methods. +/** A method involving native code that may not be called by an EJB. */ class ForbiddenNativeCodeMethod extends Method { ForbiddenNativeCodeMethod() { this instanceof SystemOrRuntimeLoadLibraryMethod or @@ -505,6 +611,10 @@ class ForbiddenNativeCodeMethod extends Method { } } +/** + * A method named `load` or `loadLibrary` declared in the class + * `java.lang.System` or `java.lang.Runtime` or a subclass thereof. + */ class SystemOrRuntimeLoadLibraryMethod extends Method { SystemOrRuntimeLoadLibraryMethod() { (this.hasName("load") or this.hasName("loadLibrary")) and @@ -525,6 +635,10 @@ class SystemOrRuntimeLoadLibraryMethod extends Method { } } +/** + * A method named `exec` declared in the class + * `java.lang.Runtime` or in a subclass thereof. + */ class RuntimeExecMethod extends Method { RuntimeExecMethod() { this.hasName("exec") and diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll index 3e28d2792c9..d13c943cb6b 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Java Server Faces annotations. */ + import default /** diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 0db24786c35..54849d2d64b 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -1,7 +1,10 @@ import java +import semmle.code.java.Maps +import SpringWeb +import SpringWebClient /** - * An annotation type that identifies Spring components. + * An annotation type that identifies Spring controllers. */ class SpringControllerAnnotation extends AnnotationType { SpringControllerAnnotation() { @@ -13,6 +16,15 @@ class SpringControllerAnnotation extends AnnotationType { } } +/** + * An annotation type that identifies Spring rest controllers. + * + * Rest controllers are the same as controllers, but imply the `@ResponseBody` annotation. + */ +class SpringRestControllerAnnotation extends SpringControllerAnnotation { + SpringRestControllerAnnotation() { hasName("RestController") } +} + /** * A class annotated, directly or indirectly, as a Spring `Controller`. */ @@ -20,6 +32,13 @@ class SpringController extends Class { SpringController() { getAnAnnotation().getType() instanceof SpringControllerAnnotation } } +/** + * A class annotated, directly or indirectly, as a Spring `RestController`. + */ +class SpringRestController extends SpringController { + SpringRestController() { getAnAnnotation().getType() instanceof SpringRestControllerAnnotation } +} + /** * A method on a Spring controller which is accessed by the Spring MVC framework. */ @@ -38,7 +57,7 @@ class SpringModelAttributeMethod extends SpringControllerMethod { // not declared with @Inherited. exists(Method superMethod | this.overrides*(superMethod) and - superMethod.hasAnnotation("org.springframework.web.bind.annotation", "ModelAttribute") + superMethod.getAnAnnotation() instanceof SpringModelAttributeAnnotation ) } } @@ -58,19 +77,180 @@ class SpringInitBinderMethod extends SpringControllerMethod { } } +/** + * An `AnnotationType` that is used to indicate a `RequestMapping`. + */ +class SpringRequestMappingAnnotationType extends AnnotationType { + SpringRequestMappingAnnotationType() { + // `@RequestMapping` used directly as an annotation. + hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") + or + // `@RequestMapping` can be used as a meta-annotation on other annotation types, e.g. GetMapping, PostMapping etc. + getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType + } +} + +/** + * An `AnnotationType` that is used to indicate a `ResponseBody`. + */ +class SpringResponseBodyAnnotationType extends AnnotationType { + SpringResponseBodyAnnotationType() { + // `@ResponseBody` used directly as an annotation. + hasQualifiedName("org.springframework.web.bind.annotation", "ResponseBody") + } +} + /** * A method on a Spring controller that is executed in response to a web request. */ class SpringRequestMappingMethod extends SpringControllerMethod { + Annotation requestMappingAnnotation; + SpringRequestMappingMethod() { // Any method that declares the @RequestMapping annotation, or overrides a method that declares // the annotation. We have to do this explicit check because the @RequestMapping annotation is // not declared with @Inherited. exists(Method superMethod | this.overrides*(superMethod) and - superMethod.hasAnnotation("org.springframework.web.bind.annotation", "RequestMapping") + requestMappingAnnotation = superMethod.getAnAnnotation() and + requestMappingAnnotation.getType() instanceof SpringRequestMappingAnnotationType ) } + + /** Gets a request mapping parameter. */ + SpringRequestMappingParameter getARequestParameter() { result = getAParameter() } + + /** Gets the "produces" @RequestMapping annotation value, if present. */ + string getProduces() { + result = + requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() + } + + /** Holds if this is considered an `@ResponseBody` method. */ + predicate isResponseBody() { + getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or + getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or + getDeclaringType() instanceof SpringRestController + } +} + +/** A Spring framework annotation indicating remote user input from servlets. */ +class SpringServletInputAnnotation extends Annotation { + SpringServletInputAnnotation() { + exists(AnnotationType a | + a = this.getType() and + a.getPackage().getName() = "org.springframework.web.bind.annotation" + | + a.hasName("MatrixVariable") or + a.hasName("RequestParam") or + a.hasName("RequestHeader") or + a.hasName("CookieValue") or + a.hasName("RequestPart") or + a.hasName("PathVariable") or + a.hasName("RequestBody") + ) + } +} + +/** An annotation of the type `org.springframework.web.bind.annotation.ModelAttribute`. */ +class SpringModelAttributeAnnotation extends Annotation { + SpringModelAttributeAnnotation() { + getType().hasQualifiedName("org.springframework.web.bind.annotation", "ModelAttribute") + } +} + +/** A parameter of a `SpringRequestMappingMethod`. */ +class SpringRequestMappingParameter extends Parameter { + SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod } + + /** Holds if the parameter should not be consider a direct source of taint. */ + predicate isNotDirectlyTaintedInput() { + getType().(RefType).getAnAncestor() instanceof SpringWebRequest or + getType().(RefType).getAnAncestor() instanceof SpringNativeWebRequest or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletRequest") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletResponse") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "HttpSession") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "PushBuilder") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.security", "Principal") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpMethod") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "Locale") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "TimeZone") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.time", "ZoneId") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "OutputStream") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Writer") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or + // Also covers BindingResult. Note, you can access the field value through this interface, which should be considered tainted + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.data.domain", "Pageable") or + this instanceof SpringModel + } + + private predicate isExplicitlyTaintedInput() { + // InputStream or Reader parameters allow access to the body of a request + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or + // The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request + this.getAnAnnotation() instanceof SpringServletInputAnnotation or + // HttpEntity is like @RequestBody, but with a wrapper including the headers + // TODO model unwrapping aspects + getType().(RefType).getASourceSupertype*() instanceof SpringHttpEntity or + this + .getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or + this + .getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") + } + + private predicate isImplicitRequestParam() { + // Any parameter which is not explicitly handled, is consider to be an `@RequestParam`, if + // it is a simple bean property + not isNotDirectlyTaintedInput() and + not isExplicitlyTaintedInput() and + ( + getType() instanceof PrimitiveType or + getType() instanceof TypeString + ) + } + + private predicate isImplicitModelAttribute() { + // Any parameter which is not explicitly handled, is consider to be an `@ModelAttribute`, if + // it is not an implicit request param + not isNotDirectlyTaintedInput() and + not isExplicitlyTaintedInput() and + not isImplicitRequestParam() + } + + /** Holds if this is an explicit or implicit `@ModelAttribute` parameter. */ + predicate isModelAttribute() { + isImplicitModelAttribute() or + getAnAnnotation() instanceof SpringModelAttributeAnnotation + } + + /** Holds if the input is tainted. */ + predicate isTaintedInput() { + isExplicitlyTaintedInput() + or + // Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if + // it is a simple bean property) or a @ModelAttribute if not + not isNotDirectlyTaintedInput() + } } /** @@ -90,7 +270,7 @@ abstract class SpringModel extends Parameter { * A `java.util.Map` can be accepted as the model parameter for a Spring `RequestMapping` method. */ class SpringModelPlainMap extends SpringModel { - SpringModelPlainMap() { getType().(RefType).hasQualifiedName("java.util", "Map") } + SpringModelPlainMap() { getType() instanceof MapType } override RefType getATypeInModel() { exists(MethodAccess methodCall | @@ -133,3 +313,39 @@ class SpringModelResponseType extends RefType { exists(SpringModel model | usesType(model.getATypeInModel(), this)) } } + +/** Strips wrapper types. */ +private RefType stripType(Type t) { + result = t or + result = stripType(t.(Array).getComponentType()) or + result = stripType(t.(ParameterizedType).getATypeArgument()) +} + +/** + * A user data type that may be populated from an HTTP request. + * + * This includes types directly referred to as either `@ModelAttribute` or `@RequestBody` parameters, + * or types that are referred to by those types. + */ +class SpringUntrustedDataType extends RefType { + SpringUntrustedDataType() { + exists(SpringRequestMappingParameter p | + p.isModelAttribute() + or + p.getAnAnnotation().(SpringServletInputAnnotation).getType().hasName("RequestBody") + | + this.fromSource() and + this = stripType(p.getType()) + ) + or + exists(SpringRestTemplateResponseEntityMethod rm | + this = stripType(rm.getAReference().getType().(ParameterizedType).getTypeArgument(0)) and + this.fromSource() + ) + or + exists(SpringUntrustedDataType mt | + this = stripType(mt.getAField().getType()) and + this.fromSource() + ) + } +} diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll new file mode 100644 index 00000000000..59016df25f8 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -0,0 +1,40 @@ +/** + * Provides classes for working with Spring classes and interfaces from + * `org.springframework.http`. + */ + +import java + +/** The class `org.springframework.http.HttpEntity` or an instantiation of it. */ +class SpringHttpEntity extends Class { + SpringHttpEntity() { + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "HttpEntity") + } +} + +/** The class `org.springframework.http.RequestEntity` or an instantiation of it. */ +class SpringRequestEntity extends Class { + SpringRequestEntity() { + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "RequestEntity") + } +} + +/** The class `org.springframework.http.ResponseEntity` or an instantiation of it. */ +class SpringResponseEntity extends Class { + SpringResponseEntity() { + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "ResponseEntity") + } +} + +/** The nested class `BodyBuilder` in `org.springframework.http.ResponseEntity`. */ +class SpringResponseEntityBodyBuilder extends Interface { + SpringResponseEntityBodyBuilder() { + this.getSourceDeclaration().getEnclosingType() instanceof SpringResponseEntity and + this.hasName("BodyBuilder") + } +} + +/** The class `org.springframework.http.HttpHeaders`. */ +class SpringHttpHeaders extends Class { + SpringHttpHeaders() { this.hasQualifiedName("org.springframework.http", "HttpHeaders") } +} diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll new file mode 100644 index 00000000000..4a71c71295e --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll @@ -0,0 +1,19 @@ +/** + * Provides classes for working with Spring web requests. + */ + +import java + +/** An interface for web requests in the Spring framework. */ +class SpringWebRequest extends Class { + SpringWebRequest() { + this.hasQualifiedName("org.springframework.web.context.request", "WebRequest") + } +} + +/** An interface for web requests in the Spring framework. */ +class SpringNativeWebRequest extends Class { + SpringNativeWebRequest() { + this.hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest") + } +} diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll new file mode 100644 index 00000000000..3a8d4bb084a --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll @@ -0,0 +1,29 @@ +/** + * Provides classes for working with Spring web clients. + */ + +import java +import SpringHttp + +/** The class `org.springframework.web.client.RestTemplate`. */ +class SpringRestTemplate extends Class { + SpringRestTemplate() { this.hasQualifiedName("org.springframework.web.client", "RestTemplate") } +} + +/** + * A method declared in `org.springframework.web.client.RestTemplate` that + * returns a `SpringResponseEntity`. + */ +class SpringRestTemplateResponseEntityMethod extends Method { + SpringRestTemplateResponseEntityMethod() { + this.getDeclaringType() instanceof SpringRestTemplate and + this.getReturnType() instanceof SpringResponseEntity + } +} + +/** The interface `org.springframework.web.reactive.function.client.WebClient`. */ +class SpringWebClient extends Interface { + SpringWebClient() { + this.hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient") + } +} diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index c9d2b6e4ddb..ea7a33151f8 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates and classes relating to encryption in Java. + */ + import java class SSLClass extends RefType { @@ -85,8 +89,10 @@ private string algorithmRegex(string algorithmString) { "((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))" } -/** Gets a blacklist of algorithms that are known to be insecure. */ -private string algorithmBlacklist() { +/** + * Gets the name of an algorithm that is known to be insecure. + */ +string getAnInsecureAlgorithmName() { result = "DES" or result = "RC2" or result = "RC4" or @@ -94,32 +100,40 @@ private string algorithmBlacklist() { result = "ARCFOUR" // a variant of RC4 } -// These are only bad if they're being used for encryption. -private string hashAlgorithmBlacklist() { +/** + * Gets the name of a hash algorithm that is insecure if it is being used for + * encryption. + */ +string getAnInsecureHashAlgorithmName() { result = "SHA1" or result = "MD5" } -private string rankedAlgorithmBlacklist(int i) { +private string rankedInsecureAlgorithm(int i) { // In this case we know these are being used for encryption, so we want to match // weak hash algorithms too. - result = rank[i](string s | s = algorithmBlacklist() or s = hashAlgorithmBlacklist()) -} - -private string algorithmBlacklistString(int i) { - i = 1 and result = rankedAlgorithmBlacklist(i) - or - result = rankedAlgorithmBlacklist(i) + "|" + algorithmBlacklistString(i - 1) -} - -/** Gets a regex for matching strings that look like they contain a blacklisted algorithm. */ -string algorithmBlacklistRegex() { result = - algorithmRegex(algorithmBlacklistString(max(int i | exists(rankedAlgorithmBlacklist(i))))) + rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName()) } -/** Gets a whitelist of algorithms that are known to be secure. */ -private string algorithmWhitelist() { +private string insecureAlgorithmString(int i) { + i = 1 and result = rankedInsecureAlgorithm(i) + or + result = rankedInsecureAlgorithm(i) + "|" + insecureAlgorithmString(i - 1) +} + +/** + * Gets the regular expression used for matching strings that look like they + * contain an algorithm that is known to be insecure. + */ +string getInsecureAlgorithmRegex() { + result = algorithmRegex(insecureAlgorithmString(max(int i | exists(rankedInsecureAlgorithm(i))))) +} + +/** + * Gets the name of an algorithm that is known to be secure. + */ +string getASecureAlgorithmName() { result = "RSA" or result = "SHA256" or result = "SHA512" or @@ -130,20 +144,50 @@ private string algorithmWhitelist() { result = "ECIES" } -private string rankedAlgorithmWhitelist(int i) { result = rank[i](algorithmWhitelist()) } +private string rankedSecureAlgorithm(int i) { result = rank[i](getASecureAlgorithmName()) } -private string algorithmWhitelistString(int i) { - i = 1 and result = rankedAlgorithmWhitelist(i) +private string secureAlgorithmString(int i) { + i = 1 and result = rankedSecureAlgorithm(i) or - result = rankedAlgorithmWhitelist(i) + "|" + algorithmWhitelistString(i - 1) + result = rankedSecureAlgorithm(i) + "|" + secureAlgorithmString(i - 1) } -/** Gets a regex for matching strings that look like they contain a whitelisted algorithm. */ -string algorithmWhitelistRegex() { - result = - algorithmRegex(algorithmWhitelistString(max(int i | exists(rankedAlgorithmWhitelist(i))))) +/** + * Gets a regular expression for matching strings that look like they + * contain an algorithm that is known to be secure. + */ +string getSecureAlgorithmRegex() { + result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i))))) } +/** + * DEPRECATED: Terminology has been updated. Use `getAnInsecureAlgorithmName()` + * instead. + */ +deprecated string algorithmBlacklist() { result = getAnInsecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use + * `getAnInsecureHashAlgorithmName()` instead. + */ +deprecated string hashAlgorithmBlacklist() { result = getAnInsecureHashAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getInsecureAlgorithmRegex()` instead. + */ +deprecated string algorithmBlacklistRegex() { result = getInsecureAlgorithmRegex() } + +/** + * DEPRECATED: Terminology has been updated. Use `getASecureAlgorithmName()` + * instead. + */ +deprecated string algorithmWhitelist() { result = getASecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getSecureAlgorithmRegex()` instead. + */ +deprecated string algorithmWhitelistRegex() { result = getSecureAlgorithmRegex() } + /** * Any use of a cryptographic element that specifies an encryption * algorithm. For example, methods returning ciphers, decryption methods, diff --git a/java/ql/src/semmle/code/java/security/FileReadWrite.qll b/java/ql/src/semmle/code/java/security/FileReadWrite.qll index 68cd987532c..f6aec6e9999 100644 --- a/java/ql/src/semmle/code/java/security/FileReadWrite.qll +++ b/java/ql/src/semmle/code/java/security/FileReadWrite.qll @@ -9,9 +9,9 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) { cie = fileReadingExpr and cie.getArgument(0) = fileAccess | - cie.getConstructedType().hasQualifiedName("java.io", "RandomAccessFile") or - cie.getConstructedType().hasQualifiedName("java.io", "FileReader") or - cie.getConstructedType().hasQualifiedName("java.io", "FileInputStream") + cie + .getConstructedType() + .hasQualifiedName("java.io", ["RandomAccessFile", "FileReader", "FileInputStream"]) ) or exists(MethodAccess ma, Method filesMethod | @@ -22,13 +22,9 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) { // represented by the first argument. filesMethod.getDeclaringType().hasQualifiedName("java.nio.file", "Files") and fileAccess = ma.getArgument(0) and - ( - filesMethod.hasName("readAllBytes") or - filesMethod.hasName("readAllLines") or - filesMethod.hasName("newBufferedReader") or - filesMethod.hasName("newInputReader") or - filesMethod.hasName("newByteChannel") - ) + filesMethod + .hasName(["readAllBytes", "readAllLines", "readString", "lines", "newBufferedReader", + "newInputStream", "newByteChannel"]) ) ) or diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll new file mode 100644 index 00000000000..6eb4858519a --- /dev/null +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -0,0 +1,48 @@ +/** Provides classes to reason about database query language injection vulnerabilities. */ + +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.frameworks.Jdbc +import semmle.code.java.frameworks.android.SQLite +import semmle.code.java.frameworks.javaee.Persistence +import semmle.code.java.frameworks.SpringJdbc +import semmle.code.java.frameworks.MyBatis +import semmle.code.java.frameworks.Hibernate + +/** A sink for database query language injection vulnerabilities. */ +abstract class QueryInjectionSink extends DataFlow::Node { } + +/** A sink for SQL injection vulnerabilities. */ +private class SqlInjectionSink extends QueryInjectionSink { + SqlInjectionSink() { + this.asExpr() instanceof SqlExpr + or + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + ma.getArgument(index) = this.asExpr() + | + index = m.(SQLiteRunner).sqlIndex() + or + m instanceof BatchUpdateVarargsMethod + or + index = 0 and jdbcSqlMethod(m) + or + index = 0 and mybatisSqlMethod(m) + or + index = 0 and hibernateSqlMethod(m) + ) + } +} + +/** A sink for Java Persistence Query Language injection vulnerabilities. */ +private class PersistenceQueryInjectionSink extends QueryInjectionSink { + PersistenceQueryInjectionSink() { + // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager` + exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.asExpr() | + call.getMethod() = em.getACreateQueryMethod() or + call.getMethod() = em.getACreateNativeQueryMethod() + // note: `createNamedQuery` is safe, as it takes only the query name, + // and named queries can only be constructed using constants as the query text + ) + } +} diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll index 042d9b436fa..555d65d2257 100644 --- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll +++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll @@ -51,7 +51,14 @@ class SafeKryo extends DataFlow2::Configuration { predicate unsafeDeserialization(MethodAccess ma, Expr sink) { exists(Method m | m = ma.getMethod() | m instanceof ObjectInputStreamReadObjectMethod and - sink = ma.getQualifier() + sink = ma.getQualifier() and + not exists(DataFlow::ExprNode node | + node.getExpr() = sink and + node + .getTypeBound() + .(RefType) + .hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream") + ) or m instanceof XMLDecoderReadObjectMethod and sink = ma.getQualifier() diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll similarity index 65% rename from java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll rename to java/ql/src/semmle/code/java/security/UrlRedirect.qll index 43a0ddb4f52..3f6609159ac 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -1,12 +1,15 @@ -import java -import semmle.code.java.frameworks.Servlets -import semmle.code.java.dataflow.DataFlow +/** Provides classes to reason about URL redirect attacks. */ -/** - * A URL redirection sink. - */ -class UrlRedirectSink extends DataFlow::ExprNode { - UrlRedirectSink() { +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.frameworks.Servlets + +/** A URL redirection sink */ +abstract class UrlRedirectSink extends DataFlow::Node { } + +/** A Servlet URL redirection sink. */ +private class ServletUrlRedirectSink extends UrlRedirectSink { + ServletUrlRedirectSink() { exists(MethodAccess ma | ma.getMethod() instanceof HttpServletResponseSendRedirectMethod and this.asExpr() = ma.getArgument(0) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 1b75b9ed649..9f5ed3fe9d6 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -1,6 +1,8 @@ import java import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView +import semmle.code.java.frameworks.spring.SpringController +import semmle.code.java.frameworks.spring.SpringHttp import semmle.code.java.dataflow.TaintTracking /* @@ -30,6 +32,48 @@ class XssSink extends DataFlow::ExprNode { m.getAReference().getArgument(1) = this.getExpr() and m.getName() = "loadDataWithBaseURL" ) ) + or + exists(SpringRequestMappingMethod requestMappingMethod, ReturnStmt rs | + requestMappingMethod = rs.getEnclosingCallable() and + this.asExpr() = rs.getResult() and + ( + not exists(requestMappingMethod.getProduces()) or + requestMappingMethod.getProduces().matches("text/%") + ) + | + // If a Spring request mapping method is either annotated with @ResponseBody (or equivalent), + // or returns a HttpEntity or sub-type, then the return value of the method is converted into + // a HTTP reponse using a HttpMessageConverter implementation. The implementation is chosen + // based on the return type of the method, and the Accept header of the request. + // + // By default, the only message converter which produces a response which is vulnerable to + // XSS is the StringHttpMessageConverter, which "Accept"s all text/* content types, including + // text/html. Therefore, if a browser request includes "text/html" in the "Accept" header, + // any String returned will be converted into a text/html response. + requestMappingMethod.isResponseBody() and + requestMappingMethod.getReturnType() instanceof TypeString + or + exists(Type returnType | + // A return type of HttpEntity or ResponseEntity represents an HTTP response with both + // a body and a set of headers. The body is subject to the same HttpMessageConverter + // process as above. + returnType = requestMappingMethod.getReturnType() and + ( + returnType instanceof SpringHttpEntity + or + returnType instanceof SpringResponseEntity + ) + | + // The type argument, representing the type of the body, is type String + returnType.(ParameterizedClass).getTypeArgument(0) instanceof TypeString + or + // Return type is a Raw class, which means no static type information on the body. In this + // case we will still treat this as an XSS sink, but rely on our taint flow steps for + // HttpEntity/ResponseEntity to only pass taint into those instances if the body type was + // String. + returnType instanceof RawClass + ) + ) } } diff --git a/java/ql/src/semmle/code/xml/XML.qll b/java/ql/src/semmle/code/xml/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/java/ql/src/semmle/code/xml/XML.qll +++ b/java/ql/src/semmle/code/xml/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected new file mode 100644 index 00000000000..b2325fa78a4 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -0,0 +1,63 @@ +edges +| MvelInjection.java:29:54:29:65 | read(...) : String | MvelInjection.java:30:28:30:37 | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:36:5:36:13 | statement | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:37:5:37:13 | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | MvelInjection.java:43:5:43:14 | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | MvelInjection.java:49:5:49:14 | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:57:5:57:18 | compiledScript | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:60:21:60:26 | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | MvelInjection.java:68:5:68:10 | script | +| MvelInjection.java:77:40:77:51 | read(...) : String | MvelInjection.java:77:7:77:52 | compileTemplate(...) | +| MvelInjection.java:81:54:81:65 | read(...) : String | MvelInjection.java:82:29:82:46 | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | MvelInjection.java:88:32:88:41 | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:95:14:95:36 | new String(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:25:15:25:26 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:29:54:29:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:34:58:34:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:41:58:41:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:48:7:48:18 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:53:20:53:31 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:65:58:65:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:72:26:72:37 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:77:40:77:51 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:81:54:81:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:86:58:86:69 | read(...) : String | +nodes +| MvelInjection.java:25:15:25:26 | read(...) | semmle.label | read(...) | +| MvelInjection.java:29:54:29:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:30:28:30:37 | expression | semmle.label | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:36:5:36:13 | statement | semmle.label | statement | +| MvelInjection.java:37:5:37:13 | statement | semmle.label | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:43:5:43:14 | expression | semmle.label | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:49:5:49:14 | expression | semmle.label | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:57:5:57:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:60:21:60:26 | script | semmle.label | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:68:5:68:10 | script | semmle.label | script | +| MvelInjection.java:72:26:72:37 | read(...) | semmle.label | read(...) | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:77:40:77:51 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:81:54:81:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:82:29:82:46 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:88:32:88:41 | expression | semmle.label | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:95:14:95:36 | new String(...) : String | semmle.label | new String(...) : String | +#select +| MvelInjection.java:25:15:25:26 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:25:15:25:26 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:30:28:30:37 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:30:28:30:37 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:36:5:36:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:36:5:36:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:37:5:37:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:37:5:37:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:43:5:43:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:43:5:43:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:49:5:49:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:49:5:49:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:57:5:57:18 | compiledScript | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:57:5:57:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:60:21:60:26 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:60:21:60:26 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:68:5:68:10 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:68:5:68:10 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:72:26:72:37 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:72:26:72:37 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:77:7:77:52 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:82:29:82:46 | compile(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:82:29:82:46 | compile(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:88:32:88:41 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:88:32:88:41 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java new file mode 100644 index 00000000000..88f9b861cae --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -0,0 +1,98 @@ +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.Socket; +import java.util.HashMap; +import javax.script.CompiledScript; +import javax.script.SimpleScriptContext; +import org.mvel2.MVEL; +import org.mvel2.MVELRuntime; +import org.mvel2.ParserContext; +import org.mvel2.compiler.CompiledAccExpression; +import org.mvel2.compiler.CompiledExpression; +import org.mvel2.compiler.ExecutableStatement; +import org.mvel2.compiler.ExpressionCompiler; +import org.mvel2.integration.impl.ImmutableDefaultFactory; +import org.mvel2.jsr223.MvelCompiledScript; +import org.mvel2.jsr223.MvelScriptEngine; +import org.mvel2.templates.CompiledTemplate; +import org.mvel2.templates.TemplateCompiler; +import org.mvel2.templates.TemplateRuntime; + +public class MvelInjection { + + public static void testWithMvelEval(Socket socket) throws IOException { + MVEL.eval(read(socket)); + } + + public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { + Serializable expression = MVEL.compileExpression(read(socket)); + MVEL.executeExpression(expression); + } + + public static void testWithExpressionCompiler(Socket socket) throws IOException { + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + ExecutableStatement statement = compiler.compile(); + statement.getValue(new Object(), new ImmutableDefaultFactory()); + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); + } + + public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + CompiledExpression expression = compiler.compile(); + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); + } + + public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { + CompiledAccExpression expression = new CompiledAccExpression( + read(socket).toCharArray(), Object.class, new ParserContext()); + expression.getValue(new Object(), new ImmutableDefaultFactory()); + } + + public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { + String input = read(socket); + + MvelScriptEngine engine = new MvelScriptEngine(); + CompiledScript compiledScript = engine.compile(input); + compiledScript.eval(); + + Serializable script = engine.compiledScript(input); + engine.evaluate(script, new SimpleScriptContext()); + } + + public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { + MvelScriptEngine engine = new MvelScriptEngine(); + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + ExecutableStatement statement = compiler.compile(); + MvelCompiledScript script = new MvelCompiledScript(engine, statement); + script.eval(new SimpleScriptContext()); + } + + public static void testTemplateRuntimeEval(Socket socket) throws Exception { + TemplateRuntime.eval(read(socket), new HashMap()); + } + + public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { + TemplateRuntime.execute( + TemplateCompiler.compileTemplate(read(socket)), new HashMap()); + } + + public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { + TemplateCompiler compiler = new TemplateCompiler(read(socket)); + TemplateRuntime.execute(compiler.compile(), new HashMap()); + } + + public static void testMvelRuntimeExecute(Socket socket) throws Exception { + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + CompiledExpression expression = compiler.compile(); + MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); + } + + public static String read(Socket socket) throws IOException { + try (InputStream is = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = is.read(bytes); + return new String(bytes, 0, n); + } + } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref new file mode 100644 index 00000000000..13d7cbd2295 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/MvelInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected new file mode 100644 index 00000000000..263d6be6c32 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected @@ -0,0 +1,27 @@ +edges +| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | +| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression | +| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression | +| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression | +| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression | +| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression | +nodes +| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:23:5:23:14 | expression | semmle.label | expression | +| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:34:5:34:14 | expression | semmle.label | expression | +| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:48:5:48:14 | expression | semmle.label | expression | +| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:59:5:59:14 | expression | semmle.label | expression | +| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:70:5:70:14 | expression | semmle.label | expression | +| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:83:5:83:14 | expression | semmle.label | expression | +#select +| SpelInjection.java:23:5:23:14 | expression | SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | SpEL injection from $@. | SpelInjection.java:15:22:15:44 | getInputStream(...) | this user input | +| SpelInjection.java:34:5:34:14 | expression | SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression | SpEL injection from $@. | SpelInjection.java:27:22:27:44 | getInputStream(...) | this user input | +| SpelInjection.java:48:5:48:14 | expression | SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression | SpEL injection from $@. | SpelInjection.java:38:22:38:44 | getInputStream(...) | this user input | +| SpelInjection.java:59:5:59:14 | expression | SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression | SpEL injection from $@. | SpelInjection.java:52:22:52:44 | getInputStream(...) | this user input | +| SpelInjection.java:70:5:70:14 | expression | SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression | SpEL injection from $@. | SpelInjection.java:63:22:63:44 | getInputStream(...) | this user input | +| SpelInjection.java:83:5:83:14 | expression | SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression | SpEL injection from $@. | SpelInjection.java:74:22:74:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java new file mode 100644 index 00000000000..9eeb552ef34 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java @@ -0,0 +1,100 @@ +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.SimpleEvaluationContext; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +public class SpelInjection { + + private static final ExpressionParser PARSER = new SpelExpressionParser(); + + public void testGetValue(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(input); + expression.getValue(); + } + + public void testGetValueWithChainedCalls(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = new SpelExpressionParser().parseExpression(input); + expression.getValue(); + } + + public void testSetValueWithRootObject(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = new SpelExpressionParser().parseExpression(input); + + Object root = new Object(); + Object value = new Object(); + expression.setValue(root, value); + } + + public void testGetValueWithStaticParser(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + expression.getValue(); + } + + public void testGetValueType(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + expression.getValueType(); + } + + public void testWithStandardEvaluationContext(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + + StandardEvaluationContext context = new StandardEvaluationContext(); + expression.getValue(context); + } + + public void testWithSimpleEvaluationContext(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); + + // the expression is evaluated in a limited context + expression.getValue(context); + } + +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref new file mode 100644 index 00000000000..95bc89c7ae6 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/SpelInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options new file mode 100644 index 00000000000..51fae354cec --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected new file mode 100644 index 00000000000..26bfa716880 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected @@ -0,0 +1,17 @@ +edges +| DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | +| DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | +| DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | +| DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | DisabledRevocationChecking.java:28:33:28:36 | flag | +nodes +| DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | semmle.label | this <.field> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | semmle.label | false : Boolean | +| DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | semmle.label | this <.method> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | semmle.label | this <.method> [flag] : Boolean | +| DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | semmle.label | parameter this [flag] : Boolean | +| DisabledRevocationChecking.java:28:33:28:36 | flag | semmle.label | flag | +| DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | semmle.label | this <.field> [flag] : Boolean | +#select +| DisabledRevocationChecking.java:17:12:17:16 | false | DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | DisabledRevocationChecking.java:28:33:28:36 | flag | Revocation checking is disabled $@. | DisabledRevocationChecking.java:17:12:17:16 | false | here | diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java new file mode 100644 index 00000000000..41b470b62d0 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java @@ -0,0 +1,80 @@ +import java.security.KeyStore; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXParameters; +import java.security.cert.PKIXRevocationChecker; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class DisabledRevocationChecking { + + private boolean flag = true; + + public void disableRevocationChecking() { + flag = false; + } + + public void testDisabledRevocationChecking(KeyStore cacerts, CertPath certPath) throws Exception { + disableRevocationChecking(); + validate(cacerts, certPath); + } + + public void validate(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(flag); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithCollectionsSingletonList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.setCertPathCheckers(Collections.singletonList(checker)); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithArraysAsList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.setCertPathCheckers(Arrays.asList(checker)); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithAddingToArrayList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + List checkers = new ArrayList<>(); + checkers.add(checker); + params.setCertPathCheckers(checkers); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithListOf(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + List checkers = List.of(checker); + params.setCertPathCheckers(checkers); + validator.validate(certPath, params); + } + + public void testAddingRevocationChecker(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.addCertPathChecker(checker); + validator.validate(certPath, params); + } + +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref new file mode 100644 index 00000000000..41cfa5cf8a9 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected new file mode 100644 index 00000000000..0dc34cc9e0e --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected @@ -0,0 +1,150 @@ +edges +| UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | UnsafeTlsVersion.java:44:44:44:52 | protocols | +| UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | UnsafeTlsVersion.java:50:38:50:61 | new String[] | +| UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | UnsafeTlsVersion.java:51:38:51:59 | new String[] | +| UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | UnsafeTlsVersion.java:52:38:52:61 | new String[] | +| UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | UnsafeTlsVersion.java:53:38:53:63 | new String[] | +| UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | UnsafeTlsVersion.java:56:29:56:65 | new String[] | +| UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | UnsafeTlsVersion.java:81:32:81:40 | protocols | +| UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | UnsafeTlsVersion.java:101:32:101:40 | protocols | +| UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | UnsafeTlsVersion.java:121:32:121:40 | protocols | +nodes +| UnsafeTlsVersion.java:16:28:16:32 | "SSL" | semmle.label | "SSL" | +| UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | semmle.label | "SSLv2" | +| UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | semmle.label | "SSLv3" | +| UnsafeTlsVersion.java:19:28:19:32 | "TLS" | semmle.label | "TLS" | +| UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | semmle.label | "TLSv1" | +| UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | semmle.label | "TLSv1.1" | +| UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:50:38:50:61 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:51:38:51:59 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:52:38:52:61 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:53:38:53:63 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:56:29:56:65 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | semmle.label | protocols | +#select +| UnsafeTlsVersion.java:16:28:16:32 | "SSL" | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | $@ is unsafe | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | SSL | +| UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | $@ is unsafe | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | SSLv2 | +| UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | $@ is unsafe | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:19:28:19:32 | "TLS" | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | $@ is unsafe | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | TLS | +| UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | $@ is unsafe | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | $@ is unsafe | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:32:39:32:43 | "TLS" | TLS | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:50:38:50:61 | new String[] | UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | UnsafeTlsVersion.java:50:38:50:61 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:51:38:51:59 | new String[] | UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | UnsafeTlsVersion.java:51:38:51:59 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:51:53:51:57 | "TLS" | TLS | +| UnsafeTlsVersion.java:52:38:52:61 | new String[] | UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | UnsafeTlsVersion.java:52:38:52:61 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:53:38:53:63 | new String[] | UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | UnsafeTlsVersion.java:53:38:53:63 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:56:29:56:65 | new String[] | UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | UnsafeTlsVersion.java:56:29:56:65 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:69:21:69:25 | "TLS" | TLS | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:89:27:89:31 | "TLS" | TLS | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:109:21:109:25 | "TLS" | TLS | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" | TLSv1.1 | diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java new file mode 100644 index 00000000000..11649621c85 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java @@ -0,0 +1,124 @@ +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +public class UnsafeTlsVersion { + + public static void testSslContextWithProtocol() throws NoSuchAlgorithmException { + + // unsafe + SSLContext.getInstance("SSL"); + SSLContext.getInstance("SSLv2"); + SSLContext.getInstance("SSLv3"); + SSLContext.getInstance("TLS"); + SSLContext.getInstance("TLSv1"); + SSLContext.getInstance("TLSv1.1"); + + // safe + SSLContext.getInstance("TLSv1.2"); + SSLContext.getInstance("TLSv1.3"); + } + + public static void testCreateSslParametersWithProtocol(String[] cipherSuites) { + + // unsafe + createSslParameters(cipherSuites, "SSLv3"); + createSslParameters(cipherSuites, "TLS"); + createSslParameters(cipherSuites, "TLSv1"); + createSslParameters(cipherSuites, "TLSv1.1"); + createSslParameters(cipherSuites, "TLSv1", "TLSv1.1", "TLSv1.2"); + createSslParameters(cipherSuites, "TLSv1.2"); + + // safe + createSslParameters(cipherSuites, "TLSv1.2"); + createSslParameters(cipherSuites, "TLSv1.3"); + } + + public static SSLParameters createSslParameters(String[] cipherSuites, String... protocols) { + return new SSLParameters(cipherSuites, protocols); + } + + public static void testSettingProtocolsForSslParameters() { + + // unsafe + new SSLParameters().setProtocols(new String[] { "SSLv3" }); + new SSLParameters().setProtocols(new String[] { "TLS" }); + new SSLParameters().setProtocols(new String[] { "TLSv1" }); + new SSLParameters().setProtocols(new String[] { "TLSv1.1" }); + + SSLParameters parameters = new SSLParameters(); + parameters.setProtocols(new String[] { "TLSv1.1", "TLSv1.2" }); + + // safe + new SSLParameters().setProtocols(new String[] { "TLSv1.2" }); + + parameters = new SSLParameters(); + parameters.setProtocols(new String[] { "TLSv1.2", "TLSv1.3" }); + } + + public static void testSettingProtocolForSslSocket() throws IOException { + + // unsafe + createSslSocket("SSLv3"); + createSslSocket("TLS"); + createSslSocket("TLSv1"); + createSslSocket("TLSv1.1"); + createSslSocket("TLSv1.1", "TLSv1.2"); + + // safe + createSslSocket("TLSv1.2"); + createSslSocket("TLSv1.3"); + } + + public static SSLSocket createSslSocket(String... protocols) throws IOException { + SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); + socket.setEnabledProtocols(protocols); + return socket; + } + + public static void testSettingProtocolForSslServerSocket() throws IOException { + + // unsafe + createSslServerSocket("SSLv3"); + createSslServerSocket("TLS"); + createSslServerSocket("TLSv1"); + createSslServerSocket("TLSv1.1"); + createSslServerSocket("TLSv1.1", "TLSv1.2"); + + // safe + createSslServerSocket("TLSv1.2"); + createSslServerSocket("TLSv1.3"); + } + + public static SSLServerSocket createSslServerSocket(String... protocols) throws IOException { + SSLServerSocket socket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(); + socket.setEnabledProtocols(protocols); + return socket; + } + + public static void testSettingProtocolForSslEngine() throws NoSuchAlgorithmException { + + // unsafe + createSslEngine("SSLv3"); + createSslEngine("TLS"); + createSslEngine("TLSv1"); + createSslEngine("TLSv1.1"); + createSslEngine("TLSv1.1", "TLSv1.2"); + + // safe + createSslEngine("TLSv1.2"); + createSslEngine("TLSv1.3"); + } + + public static SSLEngine createSslEngine(String... protocols) throws NoSuchAlgorithmException { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + engine.setEnabledProtocols(protocols); + return engine; + } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref new file mode 100644 index 00000000000..e0d69306c77 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java index b554a7bac7e..da59919fbe6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -37,4 +37,68 @@ public class SpringBootActuators { protected void configureOk2(HttpSecurity http) throws Exception { http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); } + + protected void configureOk3(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk4(HttpSecurity http) throws Exception { + http.authorizeRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/options b/java/ql/test/experimental/query-tests/security/CWE-016/options index aeef8fc5abc..3ebc054c664 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/options +++ b/java/ql/test/experimental/query-tests/security/CWE-016/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected new file mode 100644 index 00000000000..f22c0dae252 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -0,0 +1,180 @@ +edges +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr | +| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | +| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector | +| JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr | +| JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr | +| JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr | +| JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr | +| JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr | +nodes +| JndiInjection.java:30:38:30:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:34:16:34:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:35:20:35:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:36:29:36:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:41:16:41:19 | name | semmle.label | name | +| JndiInjection.java:42:20:42:23 | name | semmle.label | name | +| JndiInjection.java:43:29:43:32 | name | semmle.label | name | +| JndiInjection.java:44:16:44:19 | name | semmle.label | name | +| JndiInjection.java:45:14:45:17 | name | semmle.label | name | +| JndiInjection.java:46:22:46:25 | name | semmle.label | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:20:55:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:56:16:56:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:57:14:57:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:58:22:58:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:60:16:60:19 | name | semmle.label | name | +| JndiInjection.java:61:20:61:23 | name | semmle.label | name | +| JndiInjection.java:62:16:62:19 | name | semmle.label | name | +| JndiInjection.java:63:14:63:17 | name | semmle.label | name | +| JndiInjection.java:64:22:64:25 | name | semmle.label | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:72:16:72:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:73:20:73:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:74:16:74:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:75:14:75:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:76:22:76:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:78:16:78:19 | name | semmle.label | name | +| JndiInjection.java:79:20:79:23 | name | semmle.label | name | +| JndiInjection.java:80:16:80:19 | name | semmle.label | name | +| JndiInjection.java:81:14:81:17 | name | semmle.label | name | +| JndiInjection.java:82:22:82:25 | name | semmle.label | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:89:16:89:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:90:16:90:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:98:16:98:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:99:23:99:29 | nameStr | semmle.label | nameStr | +| JndiInjection.java:100:18:100:21 | name | semmle.label | name | +| JndiInjection.java:101:16:101:19 | name | semmle.label | name | +| JndiInjection.java:102:14:102:17 | name | semmle.label | name | +| JndiInjection.java:103:22:103:25 | name | semmle.label | name | +| JndiInjection.java:104:16:104:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:106:16:106:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:107:16:107:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:108:16:108:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:109:16:109:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:111:25:111:31 | nameStr | semmle.label | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:118:16:118:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:119:16:119:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:123:37:123:63 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | +| JndiInjection.java:128:5:128:13 | connector | semmle.label | connector | +| JndiInjection.java:132:27:132:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:135:35:135:40 | urlStr | semmle.label | urlStr | +| JndiInjection.java:140:27:140:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:143:41:143:46 | urlStr | semmle.label | urlStr | +| JndiInjection.java:148:52:148:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:151:37:151:42 | urlStr | semmle.label | urlStr | +| JndiInjection.java:156:52:156:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:159:51:159:56 | urlStr | semmle.label | urlStr | +| JndiInjection.java:164:52:164:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:167:51:167:56 | urlStr | semmle.label | urlStr | +#select +| JndiInjection.java:34:16:34:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:35:20:35:26 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:36:29:36:35 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:43:29:43:32 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:44:16:44:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:45:14:45:17 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:46:22:46:25 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:55:20:55:26 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:56:16:56:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:57:14:57:20 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:58:22:58:28 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:61:20:61:23 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:62:16:62:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:63:14:63:17 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:64:22:64:25 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:72:16:72:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:73:20:73:26 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:74:16:74:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:75:14:75:20 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:76:22:76:28 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:78:16:78:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:79:20:79:23 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:80:16:80:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:81:14:81:17 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:82:22:82:25 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:89:16:89:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:90:16:90:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:98:16:98:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:99:23:99:29 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:100:18:100:21 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:101:16:101:19 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:102:14:102:17 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:103:22:103:25 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:104:16:104:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:106:16:106:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:107:16:107:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:108:16:108:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:111:25:111:31 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:118:16:118:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input | +| JndiInjection.java:119:16:119:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input | +| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input | +| JndiInjection.java:128:5:128:13 | connector | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input | +| JndiInjection.java:135:35:135:40 | urlStr | JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:132:27:132:53 | urlStr | this user input | +| JndiInjection.java:143:41:143:46 | urlStr | JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:140:27:140:53 | urlStr | this user input | +| JndiInjection.java:151:37:151:42 | urlStr | JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:148:52:148:78 | urlStr | this user input | +| JndiInjection.java:159:51:159:56 | urlStr | JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:156:52:156:78 | urlStr | this user input | +| JndiInjection.java:167:51:167:56 | urlStr | JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:164:52:164:78 | urlStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..2fc551f7ba8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -0,0 +1,209 @@ +import java.io.IOException; +import java.util.Hashtable; +import java.util.Properties; + +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.naming.CompositeName; +import javax.naming.CompoundName; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.ldap.InitialLdapContext; + +import org.springframework.jndi.JndiTemplate; +import org.springframework.ldap.core.AttributesMapper; +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.NameClassPairCallbackHandler; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class JndiInjection { + @RequestMapping + public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialContext ctx = new InitialContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + InitialContext.doLookup(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + InitialContext.doLookup(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + @RequestMapping + public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompoundName(nameStr, new Properties()); + InitialDirContext ctx = new InitialDirContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + @RequestMapping + public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialLdapContext ctx = new InitialLdapContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + @RequestMapping + public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + JndiTemplate ctx = new JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } + + @RequestMapping + public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException { + LdapTemplate ctx = new LdapTemplate(); + Name name = new CompositeName(nameStr); + + ctx.lookup(nameStr); + ctx.lookupContext(nameStr); + ctx.findByDn(name, null); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + ctx.unbind(nameStr, true); + + ctx.search(nameStr, "", 0, true, null); + ctx.search(nameStr, "", 0, new String[] {}, (ContextMapper) new Object()); + ctx.search(nameStr, "", 0, (ContextMapper) new Object()); + ctx.search(nameStr, "", (ContextMapper) new Object()); + + ctx.searchForObject(nameStr, "", (ContextMapper) new Object()); + } + + @RequestMapping + public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } + + @RequestMapping + public void testJMXServiceUrlBad1(@RequestParam String urlStr) throws IOException { + JMXConnectorFactory.connect(new JMXServiceURL(urlStr)); + + JMXServiceURL url = new JMXServiceURL(urlStr); + JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); + connector.connect(); + } + + @RequestMapping + public void testEnvBad1(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.PROVIDER_URL, urlStr); + new InitialContext(env); + } + + @RequestMapping + public void testEnvBad2(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put("java.naming.provider.url", urlStr); + new InitialDirContext(env); + } + + @RequestMapping + public void testSpringJndiTemplatePropertiesBad1(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.put(Context.PROVIDER_URL, urlStr); + new JndiTemplate(props); + } + + @RequestMapping + public void testSpringJndiTemplatePropertiesBad2(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.setProperty("java.naming.provider.url", urlStr); + new JndiTemplate(props); + } + + @RequestMapping + public void testSpringJndiTemplatePropertiesBad3(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.setProperty("java.naming.provider.url", urlStr); + JndiTemplate template = new JndiTemplate(); + template.setEnvironment(props); + } + + @RequestMapping + public void testSpringLdapTemplateOk1(@RequestParam String nameStr) throws NamingException { + LdapTemplate ctx = new LdapTemplate(); + + ctx.unbind(nameStr); + ctx.unbind(nameStr, false); + + ctx.search(nameStr, "", 0, false, null); + ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object()); + ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object(), null); + ctx.search(nameStr, "", (NameClassPairCallbackHandler) new Object()); + ctx.search(nameStr, "", 0, new String[] {}, (AttributesMapper) new Object()); + ctx.search(nameStr, "", 0, (AttributesMapper) new Object()); + ctx.search(nameStr, "", (AttributesMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object(), null); + ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object(), null); + + ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object()); + } + + @RequestMapping + public void testEnvOk1(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.SECURITY_PRINCIPAL, urlStr); + new InitialContext(env); + } + + @RequestMapping + public void testEnvOk2(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put("java.naming.security.principal", urlStr); + new InitialContext(env); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref new file mode 100644 index 00000000000..61282fd2de8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-074/JndiInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options new file mode 100644 index 00000000000..6ce8be3e7f5 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../../stubs/spring-ldap-2.3.2 diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected new file mode 100644 index 00000000000..c0ea40f9bdb --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected @@ -0,0 +1,7 @@ +| UnsafeCertTrustTest.java:27:4:27:74 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:42:4:42:38 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:55:3:60:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:73:3:73:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:124:25:124:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:135:25:135:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:144:34:144:83 | createSocket(...) | Unsafe configuration of trusted certificates | diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref new file mode 100644 index 00000000000..f054d603787 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java new file mode 100644 index 00000000000..ff62035fd33 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java @@ -0,0 +1,162 @@ +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import java.net.Socket; +import javax.net.SocketFactory; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +//import com.rabbitmq.client.ConnectionFactory; + +public class UnsafeCertTrustTest { + + /** + * Test the implementation of trusting all server certs as a variable + */ + public SSLSocketFactory testTrustAllCertManager() { + try { + final SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); + final SSLSocketFactory socketFactory = context.getSocketFactory(); + return socketFactory; + } catch (final Exception x) { + throw new RuntimeException(x); + } + } + + /** + * Test the implementation of trusting all server certs as an anonymous class + */ + public SSLSocketFactory testTrustAllCertManagerOfVariable() { + try { + SSLContext context = SSLContext.getInstance("TLS"); + TrustManager[] serverTMs = new TrustManager[] { new X509TrustAllManager() }; + context.init(null, serverTMs, null); + + final SSLSocketFactory socketFactory = context.getSocketFactory(); + return socketFactory; + } catch (final Exception x) { + throw new RuntimeException(x); + } + } + + /** + * Test the implementation of trusting all hostnames as an anonymous class + */ + public void testTrustAllHostnameOfAnonymousClass() { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }); + } + + /** + * Test the implementation of trusting all hostnames as a variable + */ + public void testTrustAllHostnameOfVariable() { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + private static final X509TrustManager TRUST_ALL_CERTIFICATES = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // Noncompliant + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Noncompliant + } + }; + + private class X509TrustAllManager implements X509TrustManager { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // Noncompliant + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Noncompliant + } + }; + + public static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }; + + /** + * Test the endpoint identification of SSL engine is set to null + */ + public void testSSLEngineEndpointIdSetNull() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm(null); + sslEngine.setSSLParameters(sslParameters); + } + + /** + * Test the endpoint identification of SSL engine is not set + */ + public void testSSLEngineEndpointIdNotSet() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + } + + /** + * Test the endpoint identification of SSL socket is not set + */ + public void testSSLSocketEndpointIdNotSet() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + final SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + } + + /** + * Test the endpoint identification of regular socket is not set + */ + public void testSocketEndpointIdNotSet() { + SocketFactory socketFactory = SocketFactory.getDefault(); + Socket socket = socketFactory.createSocket("www.example.com", 80); + } + + // /** + // * Test the enableHostnameVerification of RabbitMQConnectionFactory is not set + // */ + // public void testEnableHostnameVerificationOfRabbitMQFactoryNotSet() { + // ConnectionFactory connectionFactory = new ConnectionFactory(); + // connectionFactory.useSslProtocol(); + // } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected new file mode 100644 index 00000000000..0e3c219ace3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected @@ -0,0 +1,2 @@ +| InsecureJavaMail.java:29:27:29:72 | getInstance(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:37:3:37:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java new file mode 100644 index 00000000000..05d700437dd --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java @@ -0,0 +1,45 @@ +import java.util.Properties; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; + +import org.apache.commons.mail.DefaultAuthenticator; +import org.apache.commons.mail.Email; +import org.apache.commons.mail.SimpleEmail; + +import java.util.Properties; + +class InsecureJavaMail { + public void testJavaMail() { + final Properties properties = new Properties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final javax.mail.Authenticator authenticator = new javax.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("username", "password"); + } + }; + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + // properties.put("mail.smtp.ssl.checkserveridentity", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + + public void testSimpleMail() { + Email email = new SimpleEmail(); + email.setHostName("config.hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("config.username", "config.password")); + email.setSSLOnConnect(true); + // email.setSSLCheckServerIdentity(true); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref new file mode 100644 index 00000000000..565779521f3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-297/InsecureJavaMail.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/options b/java/ql/test/experimental/query-tests/security/CWE-297/options new file mode 100644 index 00000000000..51c4feeca1b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-commons-email-1.6.0:${testdir}/../../../../stubs/javamail-api-1.6.2 diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected new file mode 100644 index 00000000000..a8ad32b662b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected @@ -0,0 +1 @@ +| insecure-web.xml:16:9:19:22 | init-param | Directory listing should be disabled to mitigate filename and path disclosure | diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref new file mode 100644 index 00000000000..ead6d782be8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml new file mode 100644 index 00000000000..346f98346b3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml @@ -0,0 +1,29 @@ + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + debug + 0 + + + listings + true + + 1 + + + + + default + / + + + \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected new file mode 100644 index 00000000000..8e1cc14fc1d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected @@ -0,0 +1,48 @@ +edges +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:17:19:17:22 | tree | +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:18:19:18:22 | tree | +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:20:17:20:27 | (...)... : Object | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | OgnlInjection.java:21:5:21:8 | node | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | OgnlInjection.java:22:5:22:8 | node | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:28:19:28:22 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:29:19:29:22 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:31:5:31:8 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:32:5:32:8 | tree | +| OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:37:19:37:22 | expr | +| OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:38:19:38:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:44:19:44:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:45:19:45:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:46:31:46:34 | expr | +nodes +| OgnlInjection.java:15:39:15:63 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:17:19:17:22 | tree | semmle.label | tree | +| OgnlInjection.java:18:19:18:22 | tree | semmle.label | tree | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | semmle.label | (...)... : Object | +| OgnlInjection.java:21:5:21:8 | node | semmle.label | node | +| OgnlInjection.java:22:5:22:8 | node | semmle.label | node | +| OgnlInjection.java:26:41:26:65 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:28:19:28:22 | tree | semmle.label | tree | +| OgnlInjection.java:29:19:29:22 | tree | semmle.label | tree | +| OgnlInjection.java:31:5:31:8 | tree | semmle.label | tree | +| OgnlInjection.java:32:5:32:8 | tree | semmle.label | tree | +| OgnlInjection.java:36:40:36:64 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:37:19:37:22 | expr | semmle.label | expr | +| OgnlInjection.java:38:19:38:22 | expr | semmle.label | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:44:19:44:22 | expr | semmle.label | expr | +| OgnlInjection.java:45:19:45:22 | expr | semmle.label | expr | +| OgnlInjection.java:46:31:46:34 | expr | semmle.label | expr | +#select +| OgnlInjection.java:17:19:17:22 | tree | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:17:19:17:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:18:19:18:22 | tree | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:18:19:18:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:21:5:21:8 | node | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:21:5:21:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:22:5:22:8 | node | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:22:5:22:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:28:19:28:22 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:28:19:28:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:29:19:29:22 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:29:19:29:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:31:5:31:8 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:31:5:31:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:32:5:32:8 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:32:5:32:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:37:19:37:22 | expr | OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:37:19:37:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:36:40:36:64 | expr | this user input | +| OgnlInjection.java:38:19:38:22 | expr | OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:38:19:38:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:36:40:36:64 | expr | this user input | +| OgnlInjection.java:44:19:44:22 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:44:19:44:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | +| OgnlInjection.java:45:19:45:22 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:45:19:45:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | +| OgnlInjection.java:46:31:46:34 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:46:31:46:34 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java new file mode 100644 index 00000000000..6026d7fa5e0 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java @@ -0,0 +1,48 @@ +import ognl.Node; +import ognl.Ognl; + +import java.util.HashMap; + +import com.opensymphony.xwork2.ognl.OgnlUtil; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class OgnlInjection { + @RequestMapping + public void testOgnlParseExpression(@RequestParam String expr) throws Exception { + Object tree = Ognl.parseExpression(expr); + Ognl.getValue(tree, new HashMap<>(), new Object()); + Ognl.setValue(tree, new HashMap<>(), new Object()); + + Node node = (Node) tree; + node.getValue(null, new Object()); + node.setValue(null, new Object(), new Object()); + } + + @RequestMapping + public void testOgnlCompileExpression(@RequestParam String expr) throws Exception { + Node tree = Ognl.compileExpression(null, new Object(), expr); + Ognl.getValue(tree, new HashMap<>(), new Object()); + Ognl.setValue(tree, new HashMap<>(), new Object()); + + tree.getValue(null, new Object()); + tree.setValue(null, new Object(), new Object()); + } + + @RequestMapping + public void testOgnlDirectlyToGetSet(@RequestParam String expr) throws Exception { + Ognl.getValue(expr, new Object()); + Ognl.setValue(expr, new Object(), new Object()); + } + + @RequestMapping + public void testStruts(@RequestParam String expr) throws Exception { + OgnlUtil ognl = new OgnlUtil(); + ognl.getValue(expr, new HashMap<>(), new Object()); + ognl.setValue(expr, new HashMap<>(), new Object(), new Object()); + new OgnlUtil().callMethod(expr, new HashMap<>(), new Object()); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref new file mode 100644 index 00000000000..668f3bf2797 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-917/OgnlInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/options b/java/ql/test/experimental/query-tests/security/CWE-917/options new file mode 100644 index 00000000000..ef63b56d84e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22 diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java new file mode 100644 index 00000000000..0ca2ecb43a7 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java @@ -0,0 +1,3 @@ +package ognl; + +public interface JavaSource {} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java new file mode 100644 index 00000000000..56d58f24d07 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java @@ -0,0 +1,6 @@ +package ognl; + +public interface Node extends JavaSource { + public Object getValue(OgnlContext context, Object source) throws OgnlException; + public void setValue(OgnlContext context, Object target, Object value) throws OgnlException; +} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java new file mode 100644 index 00000000000..1aa67646f92 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java @@ -0,0 +1,26 @@ +package ognl; + +import java.util.*; + +public abstract class Ognl { + public static Object parseExpression(String expression) throws OgnlException { + return new Object(); + } + + public static Object getValue(Object tree, Map context, Object root) throws OgnlException { + return new Object(); + } + + public static void setValue(Object tree, Object root, Object value) throws OgnlException {} + + public static Node compileExpression(OgnlContext context, Object root, String expression) + throws Exception { + return null; + } + + public static Object getValue(String expression, Object root) throws OgnlException { + return new Object(); + } + + public static void setValue(String expression, Object root, Object value) throws OgnlException {} +} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java new file mode 100644 index 00000000000..fad33eb8e80 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java @@ -0,0 +1,71 @@ +package ognl; + +import java.util.*; + +public class OgnlContext extends Object implements Map { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(Object key) { + return true; + } + + @Override + public boolean containsValue(Object value) { + return true; + } + + @Override + public Object get(Object key) { + return new Object(); + } + + @Override + public Object put(Object key, Object value) { + return new Object(); + } + + @Override + public Object remove(Object key) { + return new Object(); + } + + @Override + public void putAll(Map t) { } + + @Override + public void clear() {} + + @Override + public Set keySet() { + return new HashSet(); + } + + @Override + public Collection values() { + return new HashSet(); + } + + @Override + public Set entrySet() { + return new HashSet(); + } + + @Override + public boolean equals(Object o) { + return true; + } + + @Override + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java new file mode 100644 index 00000000000..447515aa58f --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java @@ -0,0 +1,3 @@ +package ognl; + +public class OgnlException extends Exception {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java new file mode 100644 index 00000000000..936be2abf7c --- /dev/null +++ b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java @@ -0,0 +1,13 @@ +package org.apache.shiro.jndi; + +import javax.naming.NamingException; + +public class JndiTemplate { + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + public Object lookup(String name, Class requiredType) throws NamingException { + return new Object(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java b/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java new file mode 100644 index 00000000000..5b1d031cf21 --- /dev/null +++ b/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java @@ -0,0 +1,16 @@ +package com.opensymphony.xwork2.ognl; + +import java.util.*; +import ognl.OgnlException; + +public class OgnlUtil { + public Object getValue(final String name, final Map context, final Object root) throws OgnlException { + return new Object(); + } + + public void setValue(final String name, final Map context, final Object root, final Object value) throws OgnlException {} + + public Object callMethod(final String name, final Map context, final Object root) throws OgnlException { + return new Object(); + } +} \ No newline at end of file diff --git a/java/ql/test/library-tests/Encryption/blacklist.expected b/java/ql/test/library-tests/Encryption/insecure.expected similarity index 100% rename from java/ql/test/library-tests/Encryption/blacklist.expected rename to java/ql/test/library-tests/Encryption/insecure.expected diff --git a/java/ql/test/library-tests/Encryption/whitelist.ql b/java/ql/test/library-tests/Encryption/insecure.ql similarity index 59% rename from java/ql/test/library-tests/Encryption/whitelist.ql rename to java/ql/test/library-tests/Encryption/insecure.ql index 6dab4caaa8f..86e7adcfba0 100644 --- a/java/ql/test/library-tests/Encryption/whitelist.ql +++ b/java/ql/test/library-tests/Encryption/insecure.ql @@ -2,5 +2,5 @@ import default import semmle.code.java.security.Encryption from StringLiteral s -where s.getLiteral().regexpMatch(algorithmWhitelistRegex()) +where s.getLiteral().regexpMatch(getInsecureAlgorithmRegex()) select s diff --git a/java/ql/test/library-tests/Encryption/whitelist.expected b/java/ql/test/library-tests/Encryption/secure.expected similarity index 100% rename from java/ql/test/library-tests/Encryption/whitelist.expected rename to java/ql/test/library-tests/Encryption/secure.expected diff --git a/java/ql/test/library-tests/Encryption/blacklist.ql b/java/ql/test/library-tests/Encryption/secure.ql similarity index 60% rename from java/ql/test/library-tests/Encryption/blacklist.ql rename to java/ql/test/library-tests/Encryption/secure.ql index c6b42287f83..16b752713a4 100644 --- a/java/ql/test/library-tests/Encryption/blacklist.ql +++ b/java/ql/test/library-tests/Encryption/secure.ql @@ -2,5 +2,5 @@ import default import semmle.code.java.security.Encryption from StringLiteral s -where s.getLiteral().regexpMatch(algorithmBlacklistRegex()) +where s.getLiteral().regexpMatch(getSecureAlgorithmRegex()) select s diff --git a/java/ql/test/library-tests/UnsafeDeserialization/Test.java b/java/ql/test/library-tests/UnsafeDeserialization/Test.java new file mode 100644 index 00000000000..bbc59f956cd --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/Test.java @@ -0,0 +1,12 @@ +import java.io.IOException; +import java.io.ObjectInputStream; +import org.apache.commons.io.serialization.ValidatingObjectInputStream; + +class Test { + public void test() throws IOException, ClassNotFoundException { + ObjectInputStream objectStream = new ObjectInputStream(null); + ObjectInputStream validating = new ValidatingObjectInputStream(null); + objectStream.readObject(); + validating.readObject(); + } +} diff --git a/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected new file mode 100644 index 00000000000..3b02e3ebe1a --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected @@ -0,0 +1 @@ +| Test.java:9:3:9:27 | readObject(...) | ObjectInputStream | diff --git a/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql new file mode 100644 index 00000000000..9433eba7f7f --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql @@ -0,0 +1,6 @@ +import default +import semmle.code.java.security.UnsafeDeserialization + +from Method m, MethodAccess ma +where ma.getMethod() = m and unsafeDeserialization(ma, _) +select ma, m.getDeclaringType().getName() diff --git a/java/ql/test/library-tests/dataflow/collections/ContainterTest.java b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java new file mode 100644 index 00000000000..ab9b699be9b --- /dev/null +++ b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java @@ -0,0 +1,228 @@ + +import java.util.Collection; +import java.util.List; +import java.util.Vector; +import java.util.Stack; +import java.util.Queue; +import java.util.Deque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TransferQueue; +import java.util.concurrent.BlockingDeque; +import java.util.SortedSet; +import java.util.NavigableSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.NavigableMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.Dictionary; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Enumeration; + +class ContainerTest { + + private static T sink(T object) { return object; } + private static T mkSink(Class cls) { return null; } + private static T source(T object) { return object; } + + public static void taintSteps( + Iterable iterable, + Collection collection, + List list, + Vector vector, + Stack stack, + Queue queue, + Deque deque, + BlockingQueue blockQueue, + BlockingDeque blockDeque, + TransferQueue transferQ, + SortedSet sortedSet, + NavigableSet navSet, + Map map, + Map.Entry entry, + SortedMap sortedMap, + NavigableMap navMap, + ConcurrentHashMap syncHashMap, + Dictionary dict, + Iterator iter, + ListIterator listIter, + Enumeration enumeration + ) throws InterruptedException { + // java.util.Iterable + sink(iterable.iterator()); + sink(iterable.spliterator()); + + // java.util.Collection + sink(collection.parallelStream()); + sink(collection.stream()); + sink(collection.toArray()); + sink(collection.toArray(x -> new String[x])); + sink(collection.toArray(new String[5])); + collection.toArray(mkSink(String[].class)); + mkSink(Collection.class).add(source("value")); + mkSink(Collection.class).addAll(collection); + + // java.util.List + sink(list.get(1)); + sink(list.listIterator()); + sink(list.listIterator(2)); + sink(list.remove(3)); + sink(list.set(4, "value")); + sink(list.subList(5, 6)); + mkSink(List.class).add(7, source("value")); + mkSink(List.class).addAll(8, collection); + mkSink(List.class).set(9, source("value")); + + // java.util.Vector + sink(vector.elementAt(7)); + sink(vector.elements()); + sink(vector.firstElement()); + sink(vector.lastElement()); + mkSink(Vector.class).addElement(source("element")); + mkSink(Vector.class).insertElementAt(source("element"), 1); + mkSink(Vector.class).setElementAt(source("element"), 2); + vector.copyInto(mkSink(String[].class)); + + // java.util.Stack + sink(stack.peek()); + sink(stack.pop()); + sink(stack.push("value")); // not tainted + sink(new Stack().push(source("value"))); + mkSink(Stack.class).push(source("value")); + + // java.util.Queue + sink(queue.element()); + sink(queue.peek()); + sink(queue.poll()); + sink(queue.remove()); + mkSink(Queue.class).offer(source("element")); + + // java.util.Deque + sink(deque.getFirst()); + sink(deque.getLast()); + sink(deque.peekFirst()); + sink(deque.peekLast()); + sink(deque.pollFirst()); + sink(deque.pollLast()); + sink(deque.removeFirst()); + sink(deque.removeLast()); + mkSink(Deque.class).addFirst(source("value")); + mkSink(Deque.class).addLast(source("value")); + mkSink(Deque.class).offerFirst(source("value")); + mkSink(Deque.class).offerLast(source("value")); + mkSink(Deque.class).push(source("value")); + + // java.util.concurrent.BlockingQueue + sink(blockQueue.poll(10, TimeUnit.SECONDS)); + sink(blockQueue.take()); + blockQueue.drainTo(mkSink(Collection.class)); + blockQueue.drainTo(mkSink(Collection.class), 4); + + // java.util.concurrent.TransferQueue + mkSink(TransferQueue.class).transfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value"), 9, TimeUnit.SECONDS); + + // java.util.concurrent.BlockingDeque + sink(blockDeque.pollFirst(11, TimeUnit.SECONDS)); + sink(blockDeque.pollLast(12, TimeUnit.SECONDS)); + sink(blockDeque.takeFirst()); + sink(blockDeque.takeLast()); + mkSink(BlockingDeque.class).offer(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).put(source("value")); + mkSink(BlockingDeque.class).offerFirst(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).offerLast(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).putFirst(source("value")); + mkSink(BlockingDeque.class).putLast(source("value")); + + // java.util.SortedSet + sink(sortedSet.first()); + sink(sortedSet.headSet("a")); + sink(sortedSet.last()); + sink(sortedSet.subSet("b", "c")); + sink(sortedSet.tailSet("d")); + + // java.util.NavigableSet + sink(navSet.ceiling("e")); + sink(navSet.descendingIterator()); + sink(navSet.descendingSet()); + sink(navSet.floor("f")); + sink(navSet.headSet("g", true)); + sink(navSet.higher("h")); + sink(navSet.lower("i")); + sink(navSet.pollFirst()); + sink(navSet.pollLast()); + sink(navSet.subSet("j", true, "k", false)); + sink(navSet.tailSet("l", true)); + + // java.util.Map + sink(map.computeIfAbsent("key", key -> "result")); + sink(map.entrySet()); + sink(map.get("key")); + sink(map.getOrDefault("key", "default")); + sink(map.merge("key", "value", (x, y) -> x + y)); + sink(map.put("key", "value")); + sink(map.putIfAbsent("key", "value")); + sink(map.remove("object")); + sink(map.replace("key", "value")); + sink(map.values()); + mkSink(Map.class).merge("key", source("v"), (x,y) -> "" + x + y); + mkSink(Map.class).put("key", source("v")); + mkSink(Map.class).putAll(map); + mkSink(Map.class).putIfAbsent("key", source("v")); + mkSink(Map.class).replace("key", source("v")); + mkSink(Map.class).replace("key", "old", source("v")); + mkSink(Map.class).replace("key", source("old"), "v"); // not tainted + + // java.util.Map.Entry + sink(entry.getValue()); + sink(entry.setValue("value")); + mkSink(Map.Entry.class).setValue(source("value")); + // java.util.SortedMap + sink(sortedMap.headMap("key")); + sink(sortedMap.subMap("key1", "key2")); + sink(sortedMap.tailMap("key")); + + // java.util.NavigableMap + sink(navMap.ceilingEntry("key")); + sink(navMap.descendingMap()); + sink(navMap.firstEntry()); + sink(navMap.floorEntry("key")); + sink(navMap.headMap("key", true)); + sink(navMap.higherEntry("key")); + sink(navMap.lastEntry()); + sink(navMap.lowerEntry("key")); + sink(navMap.pollFirstEntry()); + sink(navMap.pollLastEntry()); + sink(navMap.subMap("key1", true, "key2", true)); + sink(navMap.tailMap("key", true)); + + // java.util.concurrent.ConcurrentHashMap + sink(syncHashMap.elements()); + sink(syncHashMap.search(10, (k, v) -> v)); + sink(syncHashMap.searchEntries(11, e -> e.getValue())); + sink(syncHashMap.searchValues(12, v -> v)); + + // java.util.Dictionary + sink(dict.elements()); + sink(dict.get("object")); + sink(dict.put("key", "value")); + sink(dict.remove("object")); + mkSink(Dictionary.class).put("key", source("value")); + + // java.util.Iterator + sink(iter.next()); + + // java.util.ListIterator + sink(listIter.previous()); + mkSink(ListIterator.class).add(source("value")); + mkSink(ListIterator.class).set(source("value")); + + // java.util.Enumeration + sink(enumeration.asIterator()); + sink(enumeration.nextElement()); + } +} + diff --git a/java/ql/test/library-tests/dataflow/collections/flow.expected b/java/ql/test/library-tests/dataflow/collections/flow.expected index e2ccd7702b3..d54e9921856 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.expected +++ b/java/ql/test/library-tests/dataflow/collections/flow.expected @@ -1,3 +1,133 @@ +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:54:8:54:26 | iterator(...) | +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:55:8:55:29 | spliterator(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:58:8:58:34 | parallelStream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:59:8:59:26 | stream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:60:8:60:27 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:61:8:61:45 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:62:8:62:40 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:63:22:63:43 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:65:3:65:26 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:75:3:75:20 | mkSink(...) [post update] | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:68:8:68:18 | get(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:69:8:69:26 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:70:8:70:27 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:71:8:71:21 | remove(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:72:8:72:27 | set(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:73:8:73:25 | subList(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:79:8:79:26 | elementAt(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:80:8:80:24 | elements(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:81:8:81:28 | firstElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:82:8:82:27 | lastElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:86:19:86:40 | mkSink(...) [post update] | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:89:8:89:19 | peek(...) | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:90:8:90:18 | pop(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:96:8:96:22 | element(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:97:8:97:19 | peek(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:98:8:98:19 | poll(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:99:8:99:21 | remove(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:103:8:103:23 | getFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:104:8:104:22 | getLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:105:8:105:24 | peekFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:106:8:106:23 | peekLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:107:8:107:24 | pollFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:108:8:108:23 | pollLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:109:8:109:26 | removeFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:110:8:110:25 | removeLast(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:118:8:118:44 | poll(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:119:8:119:24 | take(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:120:22:120:45 | mkSink(...) [post update] | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:121:22:121:45 | mkSink(...) [post update] | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:129:8:129:49 | pollFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:130:8:130:48 | pollLast(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:131:8:131:29 | takeFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:132:8:132:28 | takeLast(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:141:8:141:24 | first(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:142:8:142:29 | headSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:143:8:143:23 | last(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:144:8:144:33 | subSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:145:8:145:29 | tailSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:148:8:148:26 | ceiling(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:149:8:149:34 | descendingIterator(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:150:8:150:29 | descendingSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:151:8:151:24 | floor(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:152:8:152:32 | headSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:153:8:153:25 | higher(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:154:8:154:24 | lower(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:155:8:155:25 | pollFirst(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:156:8:156:24 | pollLast(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:157:8:157:43 | subSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:158:8:158:32 | tailSet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:161:8:161:50 | computeIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:162:8:162:21 | entrySet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:163:8:163:21 | get(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:164:8:164:41 | getOrDefault(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:166:8:166:30 | put(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:167:8:167:38 | putIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:168:8:168:27 | remove(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:169:8:169:34 | replace(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:170:8:170:19 | values(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:173:3:173:19 | mkSink(...) [post update] | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:180:8:180:23 | getValue(...) | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:181:8:181:30 | setValue(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:184:8:184:31 | headMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:185:8:185:39 | subMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:186:8:186:31 | tailMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:189:8:189:33 | ceilingEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:190:8:190:29 | descendingMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:191:8:191:26 | firstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:192:8:192:31 | floorEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:193:8:193:34 | headMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:194:8:194:32 | higherEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:195:8:195:25 | lastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:196:8:196:31 | lowerEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:197:8:197:30 | pollFirstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:198:8:198:29 | pollLastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:199:8:199:48 | subMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:200:8:200:34 | tailMap(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:203:8:203:29 | elements(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:204:8:204:42 | search(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:205:8:205:55 | searchEntries(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:206:8:206:43 | searchValues(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:209:8:209:22 | elements(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:210:8:210:25 | get(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:211:8:211:31 | put(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:212:8:212:28 | remove(...) | +| ContainterTest.java:49:4:49:24 | iter | ContainterTest.java:216:8:216:18 | next(...) | +| ContainterTest.java:50:4:50:32 | listIter | ContainterTest.java:219:8:219:26 | previous(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:224:8:224:31 | asIterator(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:225:8:225:32 | nextElement(...) | +| ContainterTest.java:64:39:64:45 | "value" | ContainterTest.java:64:3:64:26 | mkSink(...) [post update] | +| ContainterTest.java:74:36:74:42 | "value" | ContainterTest.java:74:3:74:20 | mkSink(...) [post update] | +| ContainterTest.java:76:36:76:42 | "value" | ContainterTest.java:76:3:76:20 | mkSink(...) [post update] | +| ContainterTest.java:83:42:83:50 | "element" | ContainterTest.java:83:3:83:22 | mkSink(...) [post update] | +| ContainterTest.java:84:47:84:55 | "element" | ContainterTest.java:84:3:84:22 | mkSink(...) [post update] | +| ContainterTest.java:85:44:85:52 | "element" | ContainterTest.java:85:3:85:22 | mkSink(...) [post update] | +| ContainterTest.java:92:32:92:38 | "value" | ContainterTest.java:92:8:92:40 | push(...) | +| ContainterTest.java:93:35:93:41 | "value" | ContainterTest.java:93:3:93:21 | mkSink(...) [post update] | +| ContainterTest.java:100:36:100:44 | "element" | ContainterTest.java:100:3:100:21 | mkSink(...) [post update] | +| ContainterTest.java:111:39:111:45 | "value" | ContainterTest.java:111:3:111:21 | mkSink(...) [post update] | +| ContainterTest.java:112:38:112:44 | "value" | ContainterTest.java:112:3:112:21 | mkSink(...) [post update] | +| ContainterTest.java:113:41:113:47 | "value" | ContainterTest.java:113:3:113:21 | mkSink(...) [post update] | +| ContainterTest.java:114:40:114:46 | "value" | ContainterTest.java:114:3:114:21 | mkSink(...) [post update] | +| ContainterTest.java:115:35:115:41 | "value" | ContainterTest.java:115:3:115:21 | mkSink(...) [post update] | +| ContainterTest.java:124:47:124:53 | "value" | ContainterTest.java:124:3:124:29 | mkSink(...) [post update] | +| ContainterTest.java:125:50:125:56 | "value" | ContainterTest.java:125:3:125:29 | mkSink(...) [post update] | +| ContainterTest.java:126:50:126:56 | "value" | ContainterTest.java:126:3:126:29 | mkSink(...) [post update] | +| ContainterTest.java:133:44:133:50 | "value" | ContainterTest.java:133:3:133:29 | mkSink(...) [post update] | +| ContainterTest.java:134:42:134:48 | "value" | ContainterTest.java:134:3:134:29 | mkSink(...) [post update] | +| ContainterTest.java:135:49:135:55 | "value" | ContainterTest.java:135:3:135:29 | mkSink(...) [post update] | +| ContainterTest.java:136:48:136:54 | "value" | ContainterTest.java:136:3:136:29 | mkSink(...) [post update] | +| ContainterTest.java:137:47:137:53 | "value" | ContainterTest.java:137:3:137:29 | mkSink(...) [post update] | +| ContainterTest.java:138:46:138:52 | "value" | ContainterTest.java:138:3:138:29 | mkSink(...) [post update] | +| ContainterTest.java:171:41:171:43 | "v" | ContainterTest.java:171:3:171:19 | mkSink(...) [post update] | +| ContainterTest.java:172:39:172:41 | "v" | ContainterTest.java:172:3:172:19 | mkSink(...) [post update] | +| ContainterTest.java:174:47:174:49 | "v" | ContainterTest.java:174:3:174:19 | mkSink(...) [post update] | +| ContainterTest.java:175:43:175:45 | "v" | ContainterTest.java:175:3:175:19 | mkSink(...) [post update] | +| ContainterTest.java:176:50:176:52 | "v" | ContainterTest.java:176:3:176:19 | mkSink(...) [post update] | +| ContainterTest.java:182:43:182:49 | "value" | ContainterTest.java:182:3:182:25 | mkSink(...) [post update] | +| ContainterTest.java:213:46:213:52 | "value" | ContainterTest.java:213:3:213:26 | mkSink(...) [post update] | +| ContainterTest.java:220:41:220:47 | "value" | ContainterTest.java:220:3:220:28 | mkSink(...) [post update] | +| ContainterTest.java:221:41:221:47 | "value" | ContainterTest.java:221:3:221:28 | mkSink(...) [post update] | | Test.java:13:18:13:24 | tainted | Test.java:15:10:15:11 | x2 | | Test.java:13:18:13:24 | tainted | Test.java:18:10:18:11 | x3 | | Test.java:13:18:13:24 | tainted | Test.java:22:12:22:13 | x4 | diff --git a/java/ql/test/library-tests/dataflow/collections/flow.ql b/java/ql/test/library-tests/dataflow/collections/flow.ql index dab06a3d966..e485725250d 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.ql +++ b/java/ql/test/library-tests/dataflow/collections/flow.ql @@ -5,13 +5,22 @@ class Conf extends TaintTracking::Configuration { Conf() { this = "conf" } override predicate isSource(DataFlow::Node src) { - src.asExpr().(VarAccess).getVariable().hasName("tainted") + ( + src.asExpr().(VarAccess).getVariable().hasName("tainted") + or + src.asParameter().getCallable().hasName("taintSteps") + or + src.asExpr() = any(MethodAccess ma | ma.getMethod().hasName("source")).getAnArgument() + ) } override predicate isSink(DataFlow::Node sink) { exists(MethodAccess ma | sink.asExpr() = ma.getAnArgument() and ma.getMethod().hasName("sink") + or + sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = ma and + ma.getMethod().hasName("mkSink") ) } } diff --git a/java/ql/test/library-tests/dataflow/fields/F.java b/java/ql/test/library-tests/dataflow/fields/F.java new file mode 100644 index 00000000000..221d514d674 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/fields/F.java @@ -0,0 +1,38 @@ +public class F { + Object Field1; + Object Field2; + public F() { + Field1 = new Object(); + Field2 = new Object(); + } + + private void m() { + Object o = new Object(); + F f = new F(); + f.Field1 = o; + f.Field2 = o; + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow + + f = new F(); + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow + + f = new F(); + o = new Object(); + f.Field1 = o; + f.Field2 = o; + m2(f); + } + + private void m2(F f) + { + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow + } + + public static void sink(Object o) { } +} diff --git a/java/ql/test/library-tests/dataflow/fields/flow.expected b/java/ql/test/library-tests/dataflow/fields/flow.expected index 2cd605f1dea..382819fbdbb 100644 --- a/java/ql/test/library-tests/dataflow/fields/flow.expected +++ b/java/ql/test/library-tests/dataflow/fields/flow.expected @@ -26,3 +26,6 @@ | E.java:2:32:2:43 | new Object(...) | E.java:21:10:21:24 | bh2.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:24:10:24:28 | p2.data.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:30:10:30:27 | p.data.buf.content | +| F.java:5:14:5:25 | new Object(...) | F.java:20:10:20:17 | f.Field1 | +| F.java:10:16:10:27 | new Object(...) | F.java:15:10:15:17 | f.Field1 | +| F.java:24:9:24:20 | new Object(...) | F.java:33:10:33:17 | f.Field1 | diff --git a/java/ql/test/library-tests/dataflow/getter/getter.ql b/java/ql/test/library-tests/dataflow/getter/getter.ql index 22ee7be5a12..02e6920fc7e 100644 --- a/java/ql/test/library-tests/dataflow/getter/getter.ql +++ b/java/ql/test/library-tests/dataflow/getter/getter.ql @@ -6,5 +6,5 @@ import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private from Node n1, Content f, Node n2 where read(n1, f, n2) or - argumentValueFlowsThrough(n1, TContentSome(f), n2) + getterStep(n1, f, n2) select n1, n2, f diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java new file mode 100644 index 00000000000..f016cb63fd3 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java @@ -0,0 +1,23 @@ +import java.util.Arrays; +import java.util.List; + +class ArraysTest { + public static void taintSteps(String[] source) { + Arrays.asList(); + Arrays.asList("one"); + Arrays.asList("two", "three"); + Arrays.copyOf(source, 10); + Arrays.copyOfRange(source, 0, 10); + Arrays.deepToString(source); + Arrays.spliterator(source); + Arrays.stream(source); + Arrays.toString(source); + Arrays.fill(source, "value"); + Arrays.fill(source, 0, 10, "data"); + Arrays.parallelPrefix(source, (x, y) -> x + y); + Arrays.parallelPrefix(source, 0, 10, (x, y) -> x + y); + Arrays.parallelSetAll(source, x -> Integer.toString(x)); + Arrays.setAll(source, x -> Integer.toString(x)); + } +} + diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java new file mode 100644 index 00000000000..7132e0051f0 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java @@ -0,0 +1,40 @@ +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.Map; + +class CollectionsTest { + public static void taintSteps(List list, List other, Enumeration enumeration, Map map) { + Collections.addAll(list); + Collections.addAll(list, "one"); + Collections.addAll(list, "two", "three"); + Collections.addAll(list, new String[]{ "four" }); + + Collections.checkedList(list, String.class); + Collections.min(list); + Collections.enumeration(list); + Collections.list(enumeration); + Collections.singletonMap("key", "value"); + Collections.copy(list, other); + Collections.nCopies(10, "item"); + Collections.replaceAll(list, "search", "replace"); + + List.of(); + java.util.List.of("a"); + List.of("b", "c"); + java.util.List.copyOf(list); + Set.of(); + Set.of("d"); + Set.of("e" , "f"); + Set.copyOf(list); + Map.of(); + Map.of("k", "v"); + Map.of("k1", "v1", "k2", "v2"); + Map.copyOf(map); + Map.ofEntries(); + Map.ofEntries(Map.entry("k3", "v3")); + Map.ofEntries(Map.entry("k4", "v4"), Map.entry("k5", "v5")); + } +} + diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java new file mode 100644 index 00000000000..1089951f07a --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java @@ -0,0 +1,35 @@ +import org.apache.commons.codec.Encoder; +import org.apache.commons.codec.Decoder; +import org.apache.commons.codec.BinaryEncoder; +import org.apache.commons.codec.BinaryDecoder; +import org.apache.commons.codec.StringEncoder; +import org.apache.commons.codec.StringDecoder; +import java.util.Date; + +class Test { + public static void taintSteps( + Date date, + Decoder decoder, + Encoder encoder, + StringEncoder stringEncoder, + StringDecoder stringDecoder, + BinaryEncoder binEncoder, + BinaryDecoder binDecoder) throws Exception { + String string1 = "hello"; + String string2 = "world"; + + byte [] bytes1 = new byte[0]; + byte [] bytes2 = new byte[0]; + + Object obj1 = decoder.decode(string2); + Object obj2 = encoder.encode(bytes2); + + string1 = stringDecoder.decode(string2); + string1 = stringEncoder.encode(string2); + + bytes1 = binEncoder.encode(bytes2); + bytes1 = binDecoder.decode(bytes2); + + Object clone = date.clone(); + } +} diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected new file mode 100644 index 00000000000..1973eb91fe4 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -0,0 +1,65 @@ +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | asList(...) | +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | new ..[] { .. } | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:9:17:9:22 | source | ArraysTest.java:9:3:9:27 | copyOf(...) | +| ArraysTest.java:10:22:10:27 | source | ArraysTest.java:10:3:10:35 | copyOfRange(...) | +| ArraysTest.java:12:22:12:27 | source | ArraysTest.java:12:3:12:28 | spliterator(...) | +| ArraysTest.java:13:17:13:22 | source | ArraysTest.java:13:3:13:23 | stream(...) | +| ArraysTest.java:15:23:15:29 | "value" | ArraysTest.java:15:15:15:20 | source [post update] | +| ArraysTest.java:16:30:16:35 | "data" | ArraysTest.java:16:15:16:20 | source [post update] | +| ArraysTest.java:17:43:17:43 | x | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:17:47:17:47 | y | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:18:50:18:50 | x | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:18:54:18:54 | y | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:19:38:19:44 | Integer | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:19:55:19:55 | x | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:20:30:20:36 | Integer | ArraysTest.java:20:30:20:48 | toString(...) | +| ArraysTest.java:20:47:20:47 | x | ArraysTest.java:20:30:20:48 | toString(...) | +| CollectionsTest.java:10:28:10:32 | "one" | CollectionsTest.java:10:3:10:33 | new ..[] { .. } | +| CollectionsTest.java:10:28:10:32 | "one" | CollectionsTest.java:10:22:10:25 | list [post update] | +| CollectionsTest.java:11:28:11:32 | "two" | CollectionsTest.java:11:3:11:42 | new ..[] { .. } | +| CollectionsTest.java:11:28:11:32 | "two" | CollectionsTest.java:11:22:11:25 | list [post update] | +| CollectionsTest.java:11:35:11:41 | "three" | CollectionsTest.java:11:3:11:42 | new ..[] { .. } | +| CollectionsTest.java:11:35:11:41 | "three" | CollectionsTest.java:11:22:11:25 | list [post update] | +| CollectionsTest.java:12:28:12:49 | new String[] | CollectionsTest.java:12:22:12:25 | list [post update] | +| CollectionsTest.java:12:28:12:49 | {...} | CollectionsTest.java:12:28:12:49 | new String[] | +| CollectionsTest.java:12:42:12:47 | "four" | CollectionsTest.java:12:28:12:49 | {...} | +| CollectionsTest.java:14:27:14:30 | list | CollectionsTest.java:14:3:14:45 | checkedList(...) | +| CollectionsTest.java:15:19:15:22 | list | CollectionsTest.java:15:3:15:23 | min(...) | +| CollectionsTest.java:16:27:16:30 | list | CollectionsTest.java:16:3:16:31 | enumeration(...) | +| CollectionsTest.java:17:20:17:30 | enumeration | CollectionsTest.java:17:3:17:31 | list(...) | +| CollectionsTest.java:18:35:18:41 | "value" | CollectionsTest.java:18:3:18:42 | singletonMap(...) | +| CollectionsTest.java:19:26:19:30 | other | CollectionsTest.java:19:20:19:23 | list [post update] | +| CollectionsTest.java:20:27:20:32 | "item" | CollectionsTest.java:20:3:20:33 | nCopies(...) | +| CollectionsTest.java:21:42:21:50 | "replace" | CollectionsTest.java:21:26:21:29 | list [post update] | +| CollectionsTest.java:24:21:24:23 | "a" | CollectionsTest.java:24:3:24:24 | of(...) | +| CollectionsTest.java:25:11:25:13 | "b" | CollectionsTest.java:25:3:25:19 | of(...) | +| CollectionsTest.java:25:16:25:18 | "c" | CollectionsTest.java:25:3:25:19 | of(...) | +| CollectionsTest.java:26:25:26:28 | list | CollectionsTest.java:26:3:26:29 | copyOf(...) | +| CollectionsTest.java:28:10:28:12 | "d" | CollectionsTest.java:28:3:28:13 | of(...) | +| CollectionsTest.java:29:10:29:12 | "e" | CollectionsTest.java:29:3:29:19 | of(...) | +| CollectionsTest.java:29:16:29:18 | "f" | CollectionsTest.java:29:3:29:19 | of(...) | +| CollectionsTest.java:30:14:30:17 | list | CollectionsTest.java:30:3:30:18 | copyOf(...) | +| CollectionsTest.java:32:15:32:17 | "v" | CollectionsTest.java:32:3:32:18 | of(...) | +| CollectionsTest.java:33:16:33:19 | "v1" | CollectionsTest.java:33:3:33:32 | of(...) | +| CollectionsTest.java:33:28:33:31 | "v2" | CollectionsTest.java:33:3:33:32 | of(...) | +| CollectionsTest.java:34:14:34:16 | map | CollectionsTest.java:34:3:34:17 | copyOf(...) | +| CollectionsTest.java:36:17:36:37 | entry(...) | CollectionsTest.java:36:3:36:38 | new ..[] { .. } | +| CollectionsTest.java:36:17:36:37 | entry(...) | CollectionsTest.java:36:3:36:38 | ofEntries(...) | +| CollectionsTest.java:36:33:36:36 | "v3" | CollectionsTest.java:36:17:36:37 | entry(...) | +| CollectionsTest.java:37:17:37:37 | entry(...) | CollectionsTest.java:37:3:37:61 | new ..[] { .. } | +| CollectionsTest.java:37:17:37:37 | entry(...) | CollectionsTest.java:37:3:37:61 | ofEntries(...) | +| CollectionsTest.java:37:33:37:36 | "v4" | CollectionsTest.java:37:17:37:37 | entry(...) | +| CollectionsTest.java:37:40:37:60 | entry(...) | CollectionsTest.java:37:3:37:61 | new ..[] { .. } | +| CollectionsTest.java:37:40:37:60 | entry(...) | CollectionsTest.java:37:3:37:61 | ofEntries(...) | +| CollectionsTest.java:37:56:37:59 | "v5" | CollectionsTest.java:37:40:37:60 | entry(...) | +| Test.java:24:32:24:38 | string2 | Test.java:24:17:24:39 | decode(...) | +| Test.java:25:46:25:51 | bytes2 | Test.java:25:31:25:52 | encode(...) | +| Test.java:27:34:27:40 | string2 | Test.java:27:13:27:41 | decode(...) | +| Test.java:28:34:28:40 | string2 | Test.java:28:13:28:41 | encode(...) | +| Test.java:30:30:30:35 | bytes2 | Test.java:30:12:30:36 | encode(...) | +| Test.java:31:30:31:35 | bytes2 | Test.java:31:12:31:36 | decode(...) | +| Test.java:33:18:33:21 | date | Test.java:33:18:33:29 | clone(...) | diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql new file mode 100644 index 00000000000..e8cd912e58a --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql @@ -0,0 +1,6 @@ +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.internal.TaintTrackingUtil + +from DataFlow::Node src, DataFlow::Node sink +where localAdditionalTaintStep(src, sink) +select src, sink diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/options b/java/ql/test/library-tests/dataflow/local-additional-taint/options new file mode 100644 index 00000000000..f31437bcba3 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-codec-1.14 -source 14 -target 14 diff --git a/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java new file mode 100644 index 00000000000..c74dc0f434e --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java @@ -0,0 +1,14 @@ +import java.util.Objects; + +class ObjectsTest { + public static void valueSteps() { + sink(Objects.requireNonNull(source())); + sink(Objects.requireNonNull(source(), "message")); + sink(Objects.requireNonNull(source(), () -> "value1")); + sink(Objects.requireNonNullElse(source(), source())); + sink(Objects.requireNonNullElseGet(source(), () -> "value2")); + sink(Objects.toString(null, source())); + } + private static T source() { return null; } + private static void sink(Object o) {} +} diff --git a/java/ql/test/library-tests/dataflow/local-flow/flow.expected b/java/ql/test/library-tests/dataflow/local-flow/flow.expected new file mode 100644 index 00000000000..22a78a4694e --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/flow.expected @@ -0,0 +1,7 @@ +| ObjectsTest.java:5:31:5:38 | source(...) | ObjectsTest.java:5:8:5:39 | requireNonNull(...) | +| ObjectsTest.java:6:31:6:38 | source(...) | ObjectsTest.java:6:8:6:50 | requireNonNull(...) | +| ObjectsTest.java:7:31:7:38 | source(...) | ObjectsTest.java:7:8:7:55 | requireNonNull(...) | +| ObjectsTest.java:8:35:8:42 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) | +| ObjectsTest.java:8:45:8:52 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) | +| ObjectsTest.java:9:38:9:45 | source(...) | ObjectsTest.java:9:8:9:62 | requireNonNullElseGet(...) | +| ObjectsTest.java:10:31:10:38 | source(...) | ObjectsTest.java:10:8:10:39 | toString(...) | diff --git a/java/ql/test/library-tests/dataflow/local-flow/flow.ql b/java/ql/test/library-tests/dataflow/local-flow/flow.ql new file mode 100644 index 00000000000..b568a1be73d --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/flow.ql @@ -0,0 +1,21 @@ +import java +import semmle.code.java.dataflow.DataFlow + +class Conf extends DataFlow::Configuration { + Conf() { this = "conf" } + + override predicate isSource(DataFlow::Node src) { + src.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + sink.asExpr() = ma.getAnArgument() and + ma.getMethod().hasName("sink") + ) + } +} + +from Conf c, DataFlow::Node src, DataFlow::Node sink +where c.hasFlow(src, sink) +select src, sink diff --git a/java/ql/test/library-tests/dataflow/local-flow/options b/java/ql/test/library-tests/dataflow/local-flow/options new file mode 100644 index 00000000000..3f12170222c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 14 -target 14 diff --git a/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java b/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java new file mode 100644 index 00000000000..0c45863a3d2 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java @@ -0,0 +1,25 @@ +class TestSwitchExpr { + Object source() { return new Object(); } + + void sink(Object o) { } + + void test(String s) { + Object x1 = source(); + Object x2 = switch (s) { + case "a", "b", ("a" + "b") -> null; + default -> x1; + }; + Object x3 = switch (s) { + case "c", "d" -> { yield x2; } + default -> throw new RuntimeException(); + }; + Object x4 = switch (s) { + case "a", "b": + case "c", "d", ("c" + "d"): + yield x3; + default: + throw new RuntimeException(); + }; + sink(x4); + } +} diff --git a/java/ql/test/library-tests/dataflow/switchexpr/options b/java/ql/test/library-tests/dataflow/switchexpr/options new file mode 100644 index 00000000000..3f12170222c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 14 -target 14 diff --git a/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected new file mode 100644 index 00000000000..d444bae3cc7 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected @@ -0,0 +1,9 @@ +| TestSwitchExpr.java:4:15:4:22 | o | +| TestSwitchExpr.java:7:21:7:28 | source(...) | +| TestSwitchExpr.java:8:21:8:30 | switch (...) | +| TestSwitchExpr.java:10:24:10:25 | x1 | +| TestSwitchExpr.java:12:21:12:30 | switch (...) | +| TestSwitchExpr.java:13:38:13:39 | x2 | +| TestSwitchExpr.java:16:21:16:30 | switch (...) | +| TestSwitchExpr.java:19:23:19:24 | x3 | +| TestSwitchExpr.java:23:14:23:15 | x4 | diff --git a/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql new file mode 100644 index 00000000000..2a6f2cc12b8 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql @@ -0,0 +1,15 @@ +import java +import semmle.code.java.dataflow.DataFlow +import DataFlow + +class Conf extends Configuration { + Conf() { this = "qqconf" } + + override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") } + + override predicate isSink(Node n) { any() } +} + +from Conf c, Node sink +where c.hasFlow(_, sink) +select sink diff --git a/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java new file mode 100644 index 00000000000..202aaa98480 --- /dev/null +++ b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java @@ -0,0 +1,31 @@ +class TestInstanceOfPattern { + private String s = "field"; + void test(Object obj) { + if (obj instanceof String s) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test2(Object obj) { + if (!(obj instanceof String s)) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test3(Object obj) { + if (obj instanceof String s && s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test4(Object obj) { + if (obj instanceof String s || s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } +} diff --git a/java/ql/test/library-tests/ssa/adjacentUses.expected b/java/ql/test/library-tests/ssa/adjacentUses.expected index 9c40a18dd6d..d8eb355fa3c 100644 --- a/java/ql/test/library-tests/ssa/adjacentUses.expected +++ b/java/ql/test/library-tests/ssa/adjacentUses.expected @@ -30,3 +30,6 @@ | Test.java:20:14:20:14 | y | Test.java:31:14:31:14 | y | | Test.java:27:19:27:19 | i | Test.java:28:9:28:9 | i | | Test.java:28:9:28:9 | i | Test.java:27:25:27:25 | i | +| TestInstanceOfPattern.java:18:34:18:34 | s | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:28:8:28:8 | s | diff --git a/java/ql/test/library-tests/ssa/firstUse.expected b/java/ql/test/library-tests/ssa/firstUse.expected index 0295248ea6b..2d86e6ed117 100644 --- a/java/ql/test/library-tests/ssa/firstUse.expected +++ b/java/ql/test/library-tests/ssa/firstUse.expected @@ -58,3 +58,15 @@ | Test.java:27:25:27:27 | SSA def(i) | Test.java:27:19:27:19 | i | | Test.java:28:4:28:9 | SSA def(x) | Test.java:28:4:28:4 | x | | Test.java:28:4:28:9 | SSA def(x) | Test.java:31:10:31:10 | x | +| TestInstanceOfPattern.java:3:24:9:2 | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:29:4:29 | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:25:16:2 | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:31:11:31 | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:25:23:2 | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:29:18:29 | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:21:8:21:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | diff --git a/java/ql/test/library-tests/ssa/options b/java/ql/test/library-tests/ssa/options new file mode 100644 index 00000000000..266b0eadc5e --- /dev/null +++ b/java/ql/test/library-tests/ssa/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14 diff --git a/java/ql/test/library-tests/ssa/ssaDef.expected b/java/ql/test/library-tests/ssa/ssaDef.expected index 7ba272c2918..f3acbc1c2f9 100644 --- a/java/ql/test/library-tests/ssa/ssaDef.expected +++ b/java/ql/test/library-tests/ssa/ssaDef.expected @@ -91,3 +91,15 @@ | Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | | Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:25:22:25:29 | s | TestInstanceOfPattern.java:25:29:25:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | diff --git a/java/ql/test/library-tests/ssa/ssaUse.expected b/java/ql/test/library-tests/ssa/ssaUse.expected index dd3d4c1e953..b06f5eaf649 100644 --- a/java/ql/test/library-tests/ssa/ssaUse.expected +++ b/java/ql/test/library-tests/ssa/ssaUse.expected @@ -58,3 +58,17 @@ | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:19:27:19 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:25:27:25 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:28:9:28:9 | i | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:28:8:28:8 | s | diff --git a/java/ql/test/library-tests/typeflow/A.java b/java/ql/test/library-tests/typeflow/A.java index a3e3e2320b8..d4ed45df158 100644 --- a/java/ql/test/library-tests/typeflow/A.java +++ b/java/ql/test/library-tests/typeflow/A.java @@ -85,4 +85,11 @@ public class A extends ArrayList { empty.put(k, v); } } + + public void m8(Object[] xs, int i) { + if (xs[i] instanceof Integer) { + Object n = xs[i]; + Object r = n; + } + } } diff --git a/java/ql/test/library-tests/typeflow/typeflow.expected b/java/ql/test/library-tests/typeflow/typeflow.expected index a9bf42bc5ad..1f879fe37ea 100644 --- a/java/ql/test/library-tests/typeflow/typeflow.expected +++ b/java/ql/test/library-tests/typeflow/typeflow.expected @@ -12,3 +12,4 @@ | A.java:61:11:61:11 | x | Integer | false | | A.java:67:22:67:22 | x | Integer | false | | A.java:70:23:70:24 | x2 | Integer | false | +| A.java:92:18:92:18 | n | Integer | false | diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index 48d7799c9a1..c9fe368a394 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -220,4 +220,28 @@ public class C { return; } } + + private Object foo16; + + private Object getFoo16() { + return this.foo16; + } + + public static void ex16(C c) { + int[] xs = c.getFoo16() != null ? new int[5] : null; + if (c.getFoo16() != null) { + xs[0]++; // NPE - false positive + } + } + + public static final int MAXLEN = 1024; + + public void ex17() { + int[] xs = null; + // loop executes at least once + for (int i = 32; i <= MAXLEN; i *= 2) { + xs = new int[5]; + } + xs[0]++; // OK + } } diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.expected b/java/ql/test/query-tests/Nullness/NullMaybe.expected index 2ddb51dfe4c..8f72be0619f 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/java/ql/test/query-tests/Nullness/NullMaybe.expected @@ -31,5 +31,6 @@ | C.java:188:9:188:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:181:5:181:22 | Object obj | obj | C.java:181:12:181:21 | obj | this | | C.java:207:9:207:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this | | C.java:219:9:219:10 | o1 | Variable $@ may be null here as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this | +| C.java:233:7:233:8 | xs | Variable $@ may be null here because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this | | F.java:11:5:11:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this | | F.java:17:5:17:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this | diff --git a/java/ql/test/query-tests/RangeAnalysis/A.java b/java/ql/test/query-tests/RangeAnalysis/A.java index d219b85bec3..f2cb4918387 100644 --- a/java/ql/test/query-tests/RangeAnalysis/A.java +++ b/java/ql/test/query-tests/RangeAnalysis/A.java @@ -175,4 +175,23 @@ public class A { } } } + + void m14(int[] xs) { + for (int i = 0; i < xs.length + 1; i++) { + if (i == 0 && xs.length > 0) { + xs[i]++; // OK - FP + } + } + } + + void m15(int[] xs) { + for (int i = 0; i < xs.length; i++) { + int x = ++i; + int y = ++i; + if (y < xs.length) { + xs[x]++; // OK - FP + xs[y]++; // OK + } + } + } } diff --git a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected index 0c2aafdc4b1..378e9ad3336 100644 --- a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected +++ b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected @@ -10,3 +10,5 @@ | A.java:111:14:111:21 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 1. | | A.java:122:16:122:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 3. | | A.java:134:16:134:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:182:9:182:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:192:9:192:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | diff --git a/java/ql/test/query-tests/maven-dependencies/.gitignore b/java/ql/test/query-tests/maven-dependencies/.gitignore new file mode 100644 index 00000000000..25172459ba5 --- /dev/null +++ b/java/ql/test/query-tests/maven-dependencies/.gitignore @@ -0,0 +1,6 @@ +# These files are automatically generated by VS Code and should not be checked in +*/.classpath +*/.project +*/target/* +*/.settings/ +.project \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected b/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected index c275cda2e58..34e6033320c 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected @@ -1,231 +1,231 @@ edges -| LdapInjection.java:41:28:41:52 | jBad : String | LdapInjection.java:43:38:43:57 | ... + ... | -| LdapInjection.java:41:55:41:81 | jBadDN : String | LdapInjection.java:43:16:43:35 | ... + ... | -| LdapInjection.java:46:28:46:52 | jBad : String | LdapInjection.java:48:56:48:75 | ... + ... | -| LdapInjection.java:46:55:46:85 | jBadDNName : String | LdapInjection.java:48:16:48:53 | new LdapName(...) | -| LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:63:53:82 | ... + ... | -| LdapInjection.java:56:28:56:59 | jBadInitial : String | LdapInjection.java:58:29:58:55 | ... + ... | -| LdapInjection.java:61:28:61:52 | jBad : String | LdapInjection.java:63:84:63:103 | ... + ... | -| LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | LdapInjection.java:63:16:63:81 | addAll(...) | -| LdapInjection.java:66:28:66:52 | jBad : String | LdapInjection.java:70:47:70:66 | ... + ... | -| LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | LdapInjection.java:70:16:70:44 | addAll(...) | -| LdapInjection.java:73:28:73:52 | jBad : String | LdapInjection.java:75:75:75:94 | ... + ... | -| LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | LdapInjection.java:75:16:75:72 | toString(...) | -| LdapInjection.java:78:28:78:52 | jBad : String | LdapInjection.java:80:76:80:95 | ... + ... | -| LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | LdapInjection.java:80:16:80:73 | (...)... | -| LdapInjection.java:92:31:92:55 | uBad : String | LdapInjection.java:94:67:94:86 | ... + ... | -| LdapInjection.java:92:58:92:84 | uBadDN : String | LdapInjection.java:94:20:94:39 | ... + ... | -| LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | LdapInjection.java:98:58:98:88 | create(...) | -| LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | LdapInjection.java:105:14:105:14 | s | -| LdapInjection.java:101:73:101:103 | uBadROSRDN : String | LdapInjection.java:105:14:105:14 | s | -| LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | LdapInjection.java:112:14:112:14 | s | -| LdapInjection.java:108:71:108:99 | uBadSRDN : String | LdapInjection.java:112:14:112:14 | s | -| LdapInjection.java:115:31:115:55 | uBad : String | LdapInjection.java:117:69:117:88 | ... + ... | -| LdapInjection.java:115:58:115:87 | uBadDNSFR : String | LdapInjection.java:117:22:117:44 | ... + ... | -| LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | LdapInjection.java:124:19:124:19 | s | -| LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | LdapInjection.java:124:19:124:19 | s | -| LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | LdapInjection.java:131:19:131:19 | s | -| LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | LdapInjection.java:131:19:131:19 | s | -| LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | LdapInjection.java:135:58:135:115 | createNOTFilter(...) | -| LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | LdapInjection.java:139:58:139:107 | toString(...) | -| LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:145:58:145:69 | toString(...) | -| LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:152:14:152:26 | duplicate(...) | -| LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:159:14:159:26 | duplicate(...) | -| LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | LdapInjection.java:166:14:166:14 | s | -| LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:173:14:173:14 | s | -| LdapInjection.java:197:30:197:54 | sBad : String | LdapInjection.java:198:36:198:55 | ... + ... | -| LdapInjection.java:197:57:197:83 | sBadDN : String | LdapInjection.java:198:14:198:33 | ... + ... | -| LdapInjection.java:201:30:201:54 | sBad : String | LdapInjection.java:202:88:202:107 | ... + ... | -| LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | LdapInjection.java:202:20:202:85 | build(...) | -| LdapInjection.java:205:30:205:54 | sBad : String | LdapInjection.java:206:100:206:119 | ... + ... | -| LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:206:23:206:97 | build(...) | -| LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | LdapInjection.java:210:15:210:76 | filter(...) | -| LdapInjection.java:213:30:213:60 | sBadFilter : String | LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | -| LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | LdapInjection.java:214:12:214:63 | newLdapName(...) | -| LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | LdapInjection.java:218:24:218:85 | filter(...) | -| LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | LdapInjection.java:223:24:223:24 | q | -| LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:227:24:227:116 | filter(...) | -| LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:232:24:232:57 | filter(...) | -| LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | LdapInjection.java:236:12:236:66 | base(...) | -| LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | LdapInjection.java:240:24:240:98 | is(...) | -| LdapInjection.java:243:31:243:69 | sBadFilterToString : String | LdapInjection.java:244:18:244:83 | toString(...) | -| LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | LdapInjection.java:250:18:250:29 | toString(...) | -| LdapInjection.java:266:30:266:54 | aBad : String | LdapInjection.java:268:36:268:55 | ... + ... | -| LdapInjection.java:266:57:266:83 | aBadDN : String | LdapInjection.java:268:14:268:33 | ... + ... | -| LdapInjection.java:271:30:271:54 | aBad : String | LdapInjection.java:273:65:273:84 | ... + ... | -| LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | LdapInjection.java:273:14:273:62 | getName(...) | -| LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | LdapInjection.java:280:14:280:14 | s | -| LdapInjection.java:283:74:283:103 | aBadDNObj : String | LdapInjection.java:287:14:287:14 | s | -| LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | LdapInjection.java:294:14:294:24 | getBase(...) | +| LdapInjection.java:45:28:45:52 | jBad : String | LdapInjection.java:47:38:47:57 | ... + ... | +| LdapInjection.java:45:55:45:81 | jBadDN : String | LdapInjection.java:47:16:47:35 | ... + ... | +| LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:56:53:75 | ... + ... | +| LdapInjection.java:51:55:51:85 | jBadDNName : String | LdapInjection.java:53:16:53:53 | new LdapName(...) | +| LdapInjection.java:57:28:57:52 | jBad : String | LdapInjection.java:59:63:59:82 | ... + ... | +| LdapInjection.java:63:28:63:59 | jBadInitial : String | LdapInjection.java:65:29:65:55 | ... + ... | +| LdapInjection.java:69:28:69:52 | jBad : String | LdapInjection.java:71:84:71:103 | ... + ... | +| LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | LdapInjection.java:71:16:71:81 | addAll(...) | +| LdapInjection.java:75:28:75:52 | jBad : String | LdapInjection.java:79:47:79:66 | ... + ... | +| LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | LdapInjection.java:79:16:79:44 | addAll(...) | +| LdapInjection.java:83:28:83:52 | jBad : String | LdapInjection.java:85:75:85:94 | ... + ... | +| LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | LdapInjection.java:85:16:85:72 | toString(...) | +| LdapInjection.java:89:28:89:52 | jBad : String | LdapInjection.java:91:76:91:95 | ... + ... | +| LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | LdapInjection.java:91:16:91:73 | (...)... | +| LdapInjection.java:106:31:106:55 | uBad : String | LdapInjection.java:108:67:108:86 | ... + ... | +| LdapInjection.java:106:58:106:84 | uBadDN : String | LdapInjection.java:108:20:108:39 | ... + ... | +| LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | LdapInjection.java:113:58:113:88 | create(...) | +| LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | LdapInjection.java:121:14:121:14 | s | +| LdapInjection.java:117:73:117:103 | uBadROSRDN : String | LdapInjection.java:121:14:121:14 | s | +| LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | LdapInjection.java:129:14:129:14 | s | +| LdapInjection.java:125:71:125:99 | uBadSRDN : String | LdapInjection.java:129:14:129:14 | s | +| LdapInjection.java:133:31:133:55 | uBad : String | LdapInjection.java:135:69:135:88 | ... + ... | +| LdapInjection.java:133:58:133:87 | uBadDNSFR : String | LdapInjection.java:135:22:135:44 | ... + ... | +| LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | LdapInjection.java:143:19:143:19 | s | +| LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | LdapInjection.java:143:19:143:19 | s | +| LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | LdapInjection.java:151:19:151:19 | s | +| LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | LdapInjection.java:151:19:151:19 | s | +| LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | LdapInjection.java:156:58:156:115 | createNOTFilter(...) | +| LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | LdapInjection.java:161:58:161:107 | toString(...) | +| LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:168:58:168:69 | toString(...) | +| LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:176:14:176:26 | duplicate(...) | +| LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:184:14:184:26 | duplicate(...) | +| LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | LdapInjection.java:192:14:192:14 | s | +| LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:200:14:200:14 | s | +| LdapInjection.java:229:30:229:54 | sBad : String | LdapInjection.java:230:36:230:55 | ... + ... | +| LdapInjection.java:229:57:229:83 | sBadDN : String | LdapInjection.java:230:14:230:33 | ... + ... | +| LdapInjection.java:234:30:234:54 | sBad : String | LdapInjection.java:235:88:235:107 | ... + ... | +| LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | LdapInjection.java:235:20:235:85 | build(...) | +| LdapInjection.java:239:30:239:54 | sBad : String | LdapInjection.java:240:100:240:119 | ... + ... | +| LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:240:23:240:97 | build(...) | +| LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | LdapInjection.java:245:15:245:76 | filter(...) | +| LdapInjection.java:249:30:249:60 | sBadFilter : String | LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | +| LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | LdapInjection.java:250:12:250:63 | newLdapName(...) | +| LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | LdapInjection.java:255:24:255:85 | filter(...) | +| LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | LdapInjection.java:261:24:261:24 | q | +| LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:266:24:266:116 | filter(...) | +| LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:272:24:272:57 | filter(...) | +| LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | LdapInjection.java:277:12:277:66 | base(...) | +| LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | LdapInjection.java:282:24:282:98 | is(...) | +| LdapInjection.java:286:31:286:69 | sBadFilterToString : String | LdapInjection.java:287:18:287:83 | toString(...) | +| LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | LdapInjection.java:294:18:294:29 | toString(...) | +| LdapInjection.java:314:30:314:54 | aBad : String | LdapInjection.java:316:36:316:55 | ... + ... | +| LdapInjection.java:314:57:314:83 | aBadDN : String | LdapInjection.java:316:14:316:33 | ... + ... | +| LdapInjection.java:320:30:320:54 | aBad : String | LdapInjection.java:322:65:322:84 | ... + ... | +| LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | LdapInjection.java:322:14:322:62 | getName(...) | +| LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | LdapInjection.java:330:14:330:14 | s | +| LdapInjection.java:334:74:334:103 | aBadDNObj : String | LdapInjection.java:338:14:338:14 | s | +| LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | LdapInjection.java:346:14:346:24 | getBase(...) | nodes -| LdapInjection.java:41:28:41:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:41:55:41:81 | jBadDN : String | semmle.label | jBadDN : String | -| LdapInjection.java:43:16:43:35 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:43:38:43:57 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:46:28:46:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:46:55:46:85 | jBadDNName : String | semmle.label | jBadDNName : String | -| LdapInjection.java:48:16:48:53 | new LdapName(...) | semmle.label | new LdapName(...) | -| LdapInjection.java:48:56:48:75 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:45:28:45:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:45:55:45:81 | jBadDN : String | semmle.label | jBadDN : String | +| LdapInjection.java:47:16:47:35 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:47:38:47:57 | ... + ... | semmle.label | ... + ... | | LdapInjection.java:51:28:51:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:53:63:53:82 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:56:28:56:59 | jBadInitial : String | semmle.label | jBadInitial : String | -| LdapInjection.java:58:29:58:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:61:28:61:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | semmle.label | jBadDNNameAdd : String | -| LdapInjection.java:63:16:63:81 | addAll(...) | semmle.label | addAll(...) | -| LdapInjection.java:63:84:63:103 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:66:28:66:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | semmle.label | jBadDNNameAdd2 : String | -| LdapInjection.java:70:16:70:44 | addAll(...) | semmle.label | addAll(...) | -| LdapInjection.java:70:47:70:66 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:73:28:73:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | semmle.label | jBadDNNameToString : String | -| LdapInjection.java:75:16:75:72 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:75:75:75:94 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:78:28:78:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | semmle.label | jBadDNNameClone : String | -| LdapInjection.java:80:16:80:73 | (...)... | semmle.label | (...)... | -| LdapInjection.java:80:76:80:95 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:92:31:92:55 | uBad : String | semmle.label | uBad : String | -| LdapInjection.java:92:58:92:84 | uBadDN : String | semmle.label | uBadDN : String | -| LdapInjection.java:94:20:94:39 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:94:67:94:86 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | semmle.label | uBadFilterCreate : String | -| LdapInjection.java:98:58:98:88 | create(...) | semmle.label | create(...) | -| LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | semmle.label | uBadROSearchRequest : String | -| LdapInjection.java:101:73:101:103 | uBadROSRDN : String | semmle.label | uBadROSRDN : String | -| LdapInjection.java:105:14:105:14 | s | semmle.label | s | -| LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | semmle.label | uBadSearchRequest : String | -| LdapInjection.java:108:71:108:99 | uBadSRDN : String | semmle.label | uBadSRDN : String | -| LdapInjection.java:112:14:112:14 | s | semmle.label | s | -| LdapInjection.java:115:31:115:55 | uBad : String | semmle.label | uBad : String | -| LdapInjection.java:115:58:115:87 | uBadDNSFR : String | semmle.label | uBadDNSFR : String | -| LdapInjection.java:117:22:117:44 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:117:69:117:88 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | semmle.label | uBadROSearchRequestAsync : String | -| LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | semmle.label | uBadROSRDNAsync : String | -| LdapInjection.java:124:19:124:19 | s | semmle.label | s | -| LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | semmle.label | uBadSearchRequestAsync : String | -| LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | semmle.label | uBadSRDNAsync : String | -| LdapInjection.java:131:19:131:19 | s | semmle.label | s | -| LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | semmle.label | uBadFilterCreateNOT : String | -| LdapInjection.java:135:58:135:115 | createNOTFilter(...) | semmle.label | createNOTFilter(...) | -| LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | semmle.label | uBadFilterCreateToString : String | -| LdapInjection.java:139:58:139:107 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | semmle.label | uBadFilterCreateToStringBuffer : String | -| LdapInjection.java:145:58:145:69 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | semmle.label | uBadSearchRequestDuplicate : String | -| LdapInjection.java:152:14:152:26 | duplicate(...) | semmle.label | duplicate(...) | -| LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | semmle.label | uBadROSearchRequestDuplicate : String | -| LdapInjection.java:159:14:159:26 | duplicate(...) | semmle.label | duplicate(...) | -| LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | semmle.label | uBadSearchRequestSetDN : String | -| LdapInjection.java:166:14:166:14 | s | semmle.label | s | -| LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | semmle.label | uBadSearchRequestSetFilter : String | -| LdapInjection.java:173:14:173:14 | s | semmle.label | s | -| LdapInjection.java:197:30:197:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:197:57:197:83 | sBadDN : String | semmle.label | sBadDN : String | -| LdapInjection.java:198:14:198:33 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:198:36:198:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:201:30:201:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | semmle.label | sBadDNLNBuilder : String | -| LdapInjection.java:202:20:202:85 | build(...) | semmle.label | build(...) | -| LdapInjection.java:202:88:202:107 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:205:30:205:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | semmle.label | sBadDNLNBuilderAdd : String | -| LdapInjection.java:206:23:206:97 | build(...) | semmle.label | build(...) | -| LdapInjection.java:206:100:206:119 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | -| LdapInjection.java:210:15:210:76 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:213:30:213:60 | sBadFilter : String | semmle.label | sBadFilter : String | -| LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | semmle.label | sBadDNLdapUtils : String | -| LdapInjection.java:214:12:214:63 | newLdapName(...) | semmle.label | newLdapName(...) | -| LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | semmle.label | new HardcodedFilter(...) | -| LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | -| LdapInjection.java:218:24:218:85 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | semmle.label | sBadLdapQuery2 : String | -| LdapInjection.java:223:24:223:24 | q | semmle.label | q | -| LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | semmle.label | sBadLdapQueryWithFilter : String | -| LdapInjection.java:227:24:227:116 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | semmle.label | sBadLdapQueryWithFilter2 : String | -| LdapInjection.java:232:24:232:57 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | semmle.label | sBadLdapQueryBase : String | -| LdapInjection.java:236:12:236:66 | base(...) | semmle.label | base(...) | -| LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | semmle.label | sBadLdapQueryComplex : String | -| LdapInjection.java:240:24:240:98 | is(...) | semmle.label | is(...) | -| LdapInjection.java:243:31:243:69 | sBadFilterToString : String | semmle.label | sBadFilterToString : String | -| LdapInjection.java:244:18:244:83 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | semmle.label | sBadFilterEncode : String | -| LdapInjection.java:250:18:250:29 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:266:30:266:54 | aBad : String | semmle.label | aBad : String | -| LdapInjection.java:266:57:266:83 | aBadDN : String | semmle.label | aBadDN : String | -| LdapInjection.java:268:14:268:33 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:268:36:268:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:271:30:271:54 | aBad : String | semmle.label | aBad : String | -| LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | semmle.label | aBadDNObjToString : String | -| LdapInjection.java:273:14:273:62 | getName(...) | semmle.label | getName(...) | -| LdapInjection.java:273:65:273:84 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | semmle.label | aBadSearchRequest : String | -| LdapInjection.java:280:14:280:14 | s | semmle.label | s | -| LdapInjection.java:283:74:283:103 | aBadDNObj : String | semmle.label | aBadDNObj : String | -| LdapInjection.java:287:14:287:14 | s | semmle.label | s | -| LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | semmle.label | aBadDNSearchRequestGet : String | -| LdapInjection.java:294:14:294:24 | getBase(...) | semmle.label | getBase(...) | +| LdapInjection.java:51:55:51:85 | jBadDNName : String | semmle.label | jBadDNName : String | +| LdapInjection.java:53:16:53:53 | new LdapName(...) | semmle.label | new LdapName(...) | +| LdapInjection.java:53:56:53:75 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:57:28:57:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:59:63:59:82 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:63:28:63:59 | jBadInitial : String | semmle.label | jBadInitial : String | +| LdapInjection.java:65:29:65:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:69:28:69:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | semmle.label | jBadDNNameAdd : String | +| LdapInjection.java:71:16:71:81 | addAll(...) | semmle.label | addAll(...) | +| LdapInjection.java:71:84:71:103 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:75:28:75:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | semmle.label | jBadDNNameAdd2 : String | +| LdapInjection.java:79:16:79:44 | addAll(...) | semmle.label | addAll(...) | +| LdapInjection.java:79:47:79:66 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:83:28:83:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | semmle.label | jBadDNNameToString : String | +| LdapInjection.java:85:16:85:72 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:85:75:85:94 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:89:28:89:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | semmle.label | jBadDNNameClone : String | +| LdapInjection.java:91:16:91:73 | (...)... | semmle.label | (...)... | +| LdapInjection.java:91:76:91:95 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:106:31:106:55 | uBad : String | semmle.label | uBad : String | +| LdapInjection.java:106:58:106:84 | uBadDN : String | semmle.label | uBadDN : String | +| LdapInjection.java:108:20:108:39 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:108:67:108:86 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | semmle.label | uBadFilterCreate : String | +| LdapInjection.java:113:58:113:88 | create(...) | semmle.label | create(...) | +| LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | semmle.label | uBadROSearchRequest : String | +| LdapInjection.java:117:73:117:103 | uBadROSRDN : String | semmle.label | uBadROSRDN : String | +| LdapInjection.java:121:14:121:14 | s | semmle.label | s | +| LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | semmle.label | uBadSearchRequest : String | +| LdapInjection.java:125:71:125:99 | uBadSRDN : String | semmle.label | uBadSRDN : String | +| LdapInjection.java:129:14:129:14 | s | semmle.label | s | +| LdapInjection.java:133:31:133:55 | uBad : String | semmle.label | uBad : String | +| LdapInjection.java:133:58:133:87 | uBadDNSFR : String | semmle.label | uBadDNSFR : String | +| LdapInjection.java:135:22:135:44 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:135:69:135:88 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | semmle.label | uBadROSearchRequestAsync : String | +| LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | semmle.label | uBadROSRDNAsync : String | +| LdapInjection.java:143:19:143:19 | s | semmle.label | s | +| LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | semmle.label | uBadSearchRequestAsync : String | +| LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | semmle.label | uBadSRDNAsync : String | +| LdapInjection.java:151:19:151:19 | s | semmle.label | s | +| LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | semmle.label | uBadFilterCreateNOT : String | +| LdapInjection.java:156:58:156:115 | createNOTFilter(...) | semmle.label | createNOTFilter(...) | +| LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | semmle.label | uBadFilterCreateToString : String | +| LdapInjection.java:161:58:161:107 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | semmle.label | uBadFilterCreateToStringBuffer : String | +| LdapInjection.java:168:58:168:69 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | semmle.label | uBadSearchRequestDuplicate : String | +| LdapInjection.java:176:14:176:26 | duplicate(...) | semmle.label | duplicate(...) | +| LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | semmle.label | uBadROSearchRequestDuplicate : String | +| LdapInjection.java:184:14:184:26 | duplicate(...) | semmle.label | duplicate(...) | +| LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | semmle.label | uBadSearchRequestSetDN : String | +| LdapInjection.java:192:14:192:14 | s | semmle.label | s | +| LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | semmle.label | uBadSearchRequestSetFilter : String | +| LdapInjection.java:200:14:200:14 | s | semmle.label | s | +| LdapInjection.java:229:30:229:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:229:57:229:83 | sBadDN : String | semmle.label | sBadDN : String | +| LdapInjection.java:230:14:230:33 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:230:36:230:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:234:30:234:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | semmle.label | sBadDNLNBuilder : String | +| LdapInjection.java:235:20:235:85 | build(...) | semmle.label | build(...) | +| LdapInjection.java:235:88:235:107 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:239:30:239:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | semmle.label | sBadDNLNBuilderAdd : String | +| LdapInjection.java:240:23:240:97 | build(...) | semmle.label | build(...) | +| LdapInjection.java:240:100:240:119 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | +| LdapInjection.java:245:15:245:76 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:249:30:249:60 | sBadFilter : String | semmle.label | sBadFilter : String | +| LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | semmle.label | sBadDNLdapUtils : String | +| LdapInjection.java:250:12:250:63 | newLdapName(...) | semmle.label | newLdapName(...) | +| LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | semmle.label | new HardcodedFilter(...) | +| LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | +| LdapInjection.java:255:24:255:85 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | semmle.label | sBadLdapQuery2 : String | +| LdapInjection.java:261:24:261:24 | q | semmle.label | q | +| LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | semmle.label | sBadLdapQueryWithFilter : String | +| LdapInjection.java:266:24:266:116 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | semmle.label | sBadLdapQueryWithFilter2 : String | +| LdapInjection.java:272:24:272:57 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | semmle.label | sBadLdapQueryBase : String | +| LdapInjection.java:277:12:277:66 | base(...) | semmle.label | base(...) | +| LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | semmle.label | sBadLdapQueryComplex : String | +| LdapInjection.java:282:24:282:98 | is(...) | semmle.label | is(...) | +| LdapInjection.java:286:31:286:69 | sBadFilterToString : String | semmle.label | sBadFilterToString : String | +| LdapInjection.java:287:18:287:83 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | semmle.label | sBadFilterEncode : String | +| LdapInjection.java:294:18:294:29 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:314:30:314:54 | aBad : String | semmle.label | aBad : String | +| LdapInjection.java:314:57:314:83 | aBadDN : String | semmle.label | aBadDN : String | +| LdapInjection.java:316:14:316:33 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:316:36:316:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:320:30:320:54 | aBad : String | semmle.label | aBad : String | +| LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | semmle.label | aBadDNObjToString : String | +| LdapInjection.java:322:14:322:62 | getName(...) | semmle.label | getName(...) | +| LdapInjection.java:322:65:322:84 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | semmle.label | aBadSearchRequest : String | +| LdapInjection.java:330:14:330:14 | s | semmle.label | s | +| LdapInjection.java:334:74:334:103 | aBadDNObj : String | semmle.label | aBadDNObj : String | +| LdapInjection.java:338:14:338:14 | s | semmle.label | s | +| LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | semmle.label | aBadDNSearchRequestGet : String | +| LdapInjection.java:346:14:346:24 | getBase(...) | semmle.label | getBase(...) | #select -| LdapInjection.java:43:16:43:35 | ... + ... | LdapInjection.java:41:55:41:81 | jBadDN : String | LdapInjection.java:43:16:43:35 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:41:55:41:81 | jBadDN | this user input | -| LdapInjection.java:43:38:43:57 | ... + ... | LdapInjection.java:41:28:41:52 | jBad : String | LdapInjection.java:43:38:43:57 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:41:28:41:52 | jBad | this user input | -| LdapInjection.java:48:16:48:53 | new LdapName(...) | LdapInjection.java:46:55:46:85 | jBadDNName : String | LdapInjection.java:48:16:48:53 | new LdapName(...) | LDAP query might include code from $@. | LdapInjection.java:46:55:46:85 | jBadDNName | this user input | -| LdapInjection.java:48:56:48:75 | ... + ... | LdapInjection.java:46:28:46:52 | jBad : String | LdapInjection.java:48:56:48:75 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:46:28:46:52 | jBad | this user input | -| LdapInjection.java:53:63:53:82 | ... + ... | LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:63:53:82 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:51:28:51:52 | jBad | this user input | -| LdapInjection.java:58:29:58:55 | ... + ... | LdapInjection.java:56:28:56:59 | jBadInitial : String | LdapInjection.java:58:29:58:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:56:28:56:59 | jBadInitial | this user input | -| LdapInjection.java:63:16:63:81 | addAll(...) | LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | LdapInjection.java:63:16:63:81 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:61:55:61:88 | jBadDNNameAdd | this user input | -| LdapInjection.java:63:84:63:103 | ... + ... | LdapInjection.java:61:28:61:52 | jBad : String | LdapInjection.java:63:84:63:103 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:61:28:61:52 | jBad | this user input | -| LdapInjection.java:70:16:70:44 | addAll(...) | LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | LdapInjection.java:70:16:70:44 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 | this user input | -| LdapInjection.java:70:47:70:66 | ... + ... | LdapInjection.java:66:28:66:52 | jBad : String | LdapInjection.java:70:47:70:66 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:66:28:66:52 | jBad | this user input | -| LdapInjection.java:75:16:75:72 | toString(...) | LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | LdapInjection.java:75:16:75:72 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:73:55:73:93 | jBadDNNameToString | this user input | -| LdapInjection.java:75:75:75:94 | ... + ... | LdapInjection.java:73:28:73:52 | jBad : String | LdapInjection.java:75:75:75:94 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:73:28:73:52 | jBad | this user input | -| LdapInjection.java:80:16:80:73 | (...)... | LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | LdapInjection.java:80:16:80:73 | (...)... | LDAP query might include code from $@. | LdapInjection.java:78:55:78:90 | jBadDNNameClone | this user input | -| LdapInjection.java:80:76:80:95 | ... + ... | LdapInjection.java:78:28:78:52 | jBad : String | LdapInjection.java:80:76:80:95 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:78:28:78:52 | jBad | this user input | -| LdapInjection.java:94:20:94:39 | ... + ... | LdapInjection.java:92:58:92:84 | uBadDN : String | LdapInjection.java:94:20:94:39 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:92:58:92:84 | uBadDN | this user input | -| LdapInjection.java:94:67:94:86 | ... + ... | LdapInjection.java:92:31:92:55 | uBad : String | LdapInjection.java:94:67:94:86 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:92:31:92:55 | uBad | this user input | -| LdapInjection.java:98:58:98:88 | create(...) | LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | LdapInjection.java:98:58:98:88 | create(...) | LDAP query might include code from $@. | LdapInjection.java:97:31:97:67 | uBadFilterCreate | this user input | -| LdapInjection.java:105:14:105:14 | s | LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | LdapInjection.java:105:14:105:14 | s | LDAP query might include code from $@. | LdapInjection.java:101:31:101:70 | uBadROSearchRequest | this user input | -| LdapInjection.java:105:14:105:14 | s | LdapInjection.java:101:73:101:103 | uBadROSRDN : String | LdapInjection.java:105:14:105:14 | s | LDAP query might include code from $@. | LdapInjection.java:101:73:101:103 | uBadROSRDN | this user input | -| LdapInjection.java:112:14:112:14 | s | LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | LdapInjection.java:112:14:112:14 | s | LDAP query might include code from $@. | LdapInjection.java:108:31:108:68 | uBadSearchRequest | this user input | -| LdapInjection.java:112:14:112:14 | s | LdapInjection.java:108:71:108:99 | uBadSRDN : String | LdapInjection.java:112:14:112:14 | s | LDAP query might include code from $@. | LdapInjection.java:108:71:108:99 | uBadSRDN | this user input | -| LdapInjection.java:117:22:117:44 | ... + ... | LdapInjection.java:115:58:115:87 | uBadDNSFR : String | LdapInjection.java:117:22:117:44 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:115:58:115:87 | uBadDNSFR | this user input | -| LdapInjection.java:117:69:117:88 | ... + ... | LdapInjection.java:115:31:115:55 | uBad : String | LdapInjection.java:117:69:117:88 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:115:31:115:55 | uBad | this user input | -| LdapInjection.java:124:19:124:19 | s | LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | LdapInjection.java:124:19:124:19 | s | LDAP query might include code from $@. | LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync | this user input | -| LdapInjection.java:124:19:124:19 | s | LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | LdapInjection.java:124:19:124:19 | s | LDAP query might include code from $@. | LdapInjection.java:120:78:120:113 | uBadROSRDNAsync | this user input | -| LdapInjection.java:131:19:131:19 | s | LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | LdapInjection.java:131:19:131:19 | s | LDAP query might include code from $@. | LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync | this user input | -| LdapInjection.java:131:19:131:19 | s | LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | LdapInjection.java:131:19:131:19 | s | LDAP query might include code from $@. | LdapInjection.java:127:76:127:109 | uBadSRDNAsync | this user input | -| LdapInjection.java:135:58:135:115 | createNOTFilter(...) | LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | LdapInjection.java:135:58:135:115 | createNOTFilter(...) | LDAP query might include code from $@. | LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT | this user input | -| LdapInjection.java:139:58:139:107 | toString(...) | LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | LdapInjection.java:139:58:139:107 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:138:31:138:75 | uBadFilterCreateToString | this user input | -| LdapInjection.java:145:58:145:69 | toString(...) | LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:145:58:145:69 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer | this user input | -| LdapInjection.java:152:14:152:26 | duplicate(...) | LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:152:14:152:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate | this user input | -| LdapInjection.java:159:14:159:26 | duplicate(...) | LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:159:14:159:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate | this user input | -| LdapInjection.java:166:14:166:14 | s | LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | LdapInjection.java:166:14:166:14 | s | LDAP query might include code from $@. | LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN | this user input | -| LdapInjection.java:173:14:173:14 | s | LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:173:14:173:14 | s | LDAP query might include code from $@. | LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter | this user input | -| LdapInjection.java:198:14:198:33 | ... + ... | LdapInjection.java:197:57:197:83 | sBadDN : String | LdapInjection.java:198:14:198:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:197:57:197:83 | sBadDN | this user input | -| LdapInjection.java:198:36:198:55 | ... + ... | LdapInjection.java:197:30:197:54 | sBad : String | LdapInjection.java:198:36:198:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:197:30:197:54 | sBad | this user input | -| LdapInjection.java:202:20:202:85 | build(...) | LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | LdapInjection.java:202:20:202:85 | build(...) | LDAP query might include code from $@. | LdapInjection.java:201:57:201:92 | sBadDNLNBuilder | this user input | -| LdapInjection.java:202:88:202:107 | ... + ... | LdapInjection.java:201:30:201:54 | sBad : String | LdapInjection.java:202:88:202:107 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:201:30:201:54 | sBad | this user input | -| LdapInjection.java:206:23:206:97 | build(...) | LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:206:23:206:97 | build(...) | LDAP query might include code from $@. | LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd | this user input | -| LdapInjection.java:206:100:206:119 | ... + ... | LdapInjection.java:205:30:205:54 | sBad : String | LdapInjection.java:206:100:206:119 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:205:30:205:54 | sBad | this user input | -| LdapInjection.java:210:15:210:76 | filter(...) | LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | LdapInjection.java:210:15:210:76 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:209:30:209:63 | sBadLdapQuery | this user input | -| LdapInjection.java:214:12:214:63 | newLdapName(...) | LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | LdapInjection.java:214:12:214:63 | newLdapName(...) | LDAP query might include code from $@. | LdapInjection.java:213:63:213:98 | sBadDNLdapUtils | this user input | -| LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | LdapInjection.java:213:30:213:60 | sBadFilter : String | LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | LDAP query might include code from $@. | LdapInjection.java:213:30:213:60 | sBadFilter | this user input | -| LdapInjection.java:218:24:218:85 | filter(...) | LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | LdapInjection.java:218:24:218:85 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:217:30:217:63 | sBadLdapQuery | this user input | -| LdapInjection.java:223:24:223:24 | q | LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | LdapInjection.java:223:24:223:24 | q | LDAP query might include code from $@. | LdapInjection.java:221:30:221:64 | sBadLdapQuery2 | this user input | -| LdapInjection.java:227:24:227:116 | filter(...) | LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:227:24:227:116 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter | this user input | -| LdapInjection.java:232:24:232:57 | filter(...) | LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:232:24:232:57 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 | this user input | -| LdapInjection.java:236:12:236:66 | base(...) | LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | LdapInjection.java:236:12:236:66 | base(...) | LDAP query might include code from $@. | LdapInjection.java:235:31:235:68 | sBadLdapQueryBase | this user input | -| LdapInjection.java:240:24:240:98 | is(...) | LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | LdapInjection.java:240:24:240:98 | is(...) | LDAP query might include code from $@. | LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex | this user input | -| LdapInjection.java:244:18:244:83 | toString(...) | LdapInjection.java:243:31:243:69 | sBadFilterToString : String | LdapInjection.java:244:18:244:83 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:243:31:243:69 | sBadFilterToString | this user input | -| LdapInjection.java:250:18:250:29 | toString(...) | LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | LdapInjection.java:250:18:250:29 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:247:31:247:67 | sBadFilterEncode | this user input | -| LdapInjection.java:268:14:268:33 | ... + ... | LdapInjection.java:266:57:266:83 | aBadDN : String | LdapInjection.java:268:14:268:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:266:57:266:83 | aBadDN | this user input | -| LdapInjection.java:268:36:268:55 | ... + ... | LdapInjection.java:266:30:266:54 | aBad : String | LdapInjection.java:268:36:268:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:266:30:266:54 | aBad | this user input | -| LdapInjection.java:273:14:273:62 | getName(...) | LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | LdapInjection.java:273:14:273:62 | getName(...) | LDAP query might include code from $@. | LdapInjection.java:271:57:271:94 | aBadDNObjToString | this user input | -| LdapInjection.java:273:65:273:84 | ... + ... | LdapInjection.java:271:30:271:54 | aBad : String | LdapInjection.java:273:65:273:84 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:271:30:271:54 | aBad | this user input | -| LdapInjection.java:280:14:280:14 | s | LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | LdapInjection.java:280:14:280:14 | s | LDAP query might include code from $@. | LdapInjection.java:276:30:276:67 | aBadSearchRequest | this user input | -| LdapInjection.java:287:14:287:14 | s | LdapInjection.java:283:74:283:103 | aBadDNObj : String | LdapInjection.java:287:14:287:14 | s | LDAP query might include code from $@. | LdapInjection.java:283:74:283:103 | aBadDNObj | this user input | -| LdapInjection.java:294:14:294:24 | getBase(...) | LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | LdapInjection.java:294:14:294:24 | getBase(...) | LDAP query might include code from $@. | LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet | this user input | +| LdapInjection.java:47:16:47:35 | ... + ... | LdapInjection.java:45:55:45:81 | jBadDN : String | LdapInjection.java:47:16:47:35 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:45:55:45:81 | jBadDN | this user input | +| LdapInjection.java:47:38:47:57 | ... + ... | LdapInjection.java:45:28:45:52 | jBad : String | LdapInjection.java:47:38:47:57 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:45:28:45:52 | jBad | this user input | +| LdapInjection.java:53:16:53:53 | new LdapName(...) | LdapInjection.java:51:55:51:85 | jBadDNName : String | LdapInjection.java:53:16:53:53 | new LdapName(...) | LDAP query might include code from $@. | LdapInjection.java:51:55:51:85 | jBadDNName | this user input | +| LdapInjection.java:53:56:53:75 | ... + ... | LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:56:53:75 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:51:28:51:52 | jBad | this user input | +| LdapInjection.java:59:63:59:82 | ... + ... | LdapInjection.java:57:28:57:52 | jBad : String | LdapInjection.java:59:63:59:82 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:57:28:57:52 | jBad | this user input | +| LdapInjection.java:65:29:65:55 | ... + ... | LdapInjection.java:63:28:63:59 | jBadInitial : String | LdapInjection.java:65:29:65:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:63:28:63:59 | jBadInitial | this user input | +| LdapInjection.java:71:16:71:81 | addAll(...) | LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | LdapInjection.java:71:16:71:81 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:69:55:69:88 | jBadDNNameAdd | this user input | +| LdapInjection.java:71:84:71:103 | ... + ... | LdapInjection.java:69:28:69:52 | jBad : String | LdapInjection.java:71:84:71:103 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:69:28:69:52 | jBad | this user input | +| LdapInjection.java:79:16:79:44 | addAll(...) | LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | LdapInjection.java:79:16:79:44 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 | this user input | +| LdapInjection.java:79:47:79:66 | ... + ... | LdapInjection.java:75:28:75:52 | jBad : String | LdapInjection.java:79:47:79:66 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:75:28:75:52 | jBad | this user input | +| LdapInjection.java:85:16:85:72 | toString(...) | LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | LdapInjection.java:85:16:85:72 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:83:55:83:93 | jBadDNNameToString | this user input | +| LdapInjection.java:85:75:85:94 | ... + ... | LdapInjection.java:83:28:83:52 | jBad : String | LdapInjection.java:85:75:85:94 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:83:28:83:52 | jBad | this user input | +| LdapInjection.java:91:16:91:73 | (...)... | LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | LdapInjection.java:91:16:91:73 | (...)... | LDAP query might include code from $@. | LdapInjection.java:89:55:89:90 | jBadDNNameClone | this user input | +| LdapInjection.java:91:76:91:95 | ... + ... | LdapInjection.java:89:28:89:52 | jBad : String | LdapInjection.java:91:76:91:95 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:89:28:89:52 | jBad | this user input | +| LdapInjection.java:108:20:108:39 | ... + ... | LdapInjection.java:106:58:106:84 | uBadDN : String | LdapInjection.java:108:20:108:39 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:106:58:106:84 | uBadDN | this user input | +| LdapInjection.java:108:67:108:86 | ... + ... | LdapInjection.java:106:31:106:55 | uBad : String | LdapInjection.java:108:67:108:86 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:106:31:106:55 | uBad | this user input | +| LdapInjection.java:113:58:113:88 | create(...) | LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | LdapInjection.java:113:58:113:88 | create(...) | LDAP query might include code from $@. | LdapInjection.java:112:31:112:67 | uBadFilterCreate | this user input | +| LdapInjection.java:121:14:121:14 | s | LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | LdapInjection.java:121:14:121:14 | s | LDAP query might include code from $@. | LdapInjection.java:117:31:117:70 | uBadROSearchRequest | this user input | +| LdapInjection.java:121:14:121:14 | s | LdapInjection.java:117:73:117:103 | uBadROSRDN : String | LdapInjection.java:121:14:121:14 | s | LDAP query might include code from $@. | LdapInjection.java:117:73:117:103 | uBadROSRDN | this user input | +| LdapInjection.java:129:14:129:14 | s | LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | LdapInjection.java:129:14:129:14 | s | LDAP query might include code from $@. | LdapInjection.java:125:31:125:68 | uBadSearchRequest | this user input | +| LdapInjection.java:129:14:129:14 | s | LdapInjection.java:125:71:125:99 | uBadSRDN : String | LdapInjection.java:129:14:129:14 | s | LDAP query might include code from $@. | LdapInjection.java:125:71:125:99 | uBadSRDN | this user input | +| LdapInjection.java:135:22:135:44 | ... + ... | LdapInjection.java:133:58:133:87 | uBadDNSFR : String | LdapInjection.java:135:22:135:44 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:133:58:133:87 | uBadDNSFR | this user input | +| LdapInjection.java:135:69:135:88 | ... + ... | LdapInjection.java:133:31:133:55 | uBad : String | LdapInjection.java:135:69:135:88 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:133:31:133:55 | uBad | this user input | +| LdapInjection.java:143:19:143:19 | s | LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | LdapInjection.java:143:19:143:19 | s | LDAP query might include code from $@. | LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync | this user input | +| LdapInjection.java:143:19:143:19 | s | LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | LdapInjection.java:143:19:143:19 | s | LDAP query might include code from $@. | LdapInjection.java:139:78:139:113 | uBadROSRDNAsync | this user input | +| LdapInjection.java:151:19:151:19 | s | LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | LdapInjection.java:151:19:151:19 | s | LDAP query might include code from $@. | LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync | this user input | +| LdapInjection.java:151:19:151:19 | s | LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | LdapInjection.java:151:19:151:19 | s | LDAP query might include code from $@. | LdapInjection.java:147:76:147:109 | uBadSRDNAsync | this user input | +| LdapInjection.java:156:58:156:115 | createNOTFilter(...) | LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | LdapInjection.java:156:58:156:115 | createNOTFilter(...) | LDAP query might include code from $@. | LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT | this user input | +| LdapInjection.java:161:58:161:107 | toString(...) | LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | LdapInjection.java:161:58:161:107 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:160:31:160:75 | uBadFilterCreateToString | this user input | +| LdapInjection.java:168:58:168:69 | toString(...) | LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:168:58:168:69 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer | this user input | +| LdapInjection.java:176:14:176:26 | duplicate(...) | LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:176:14:176:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate | this user input | +| LdapInjection.java:184:14:184:26 | duplicate(...) | LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:184:14:184:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate | this user input | +| LdapInjection.java:192:14:192:14 | s | LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | LdapInjection.java:192:14:192:14 | s | LDAP query might include code from $@. | LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN | this user input | +| LdapInjection.java:200:14:200:14 | s | LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:200:14:200:14 | s | LDAP query might include code from $@. | LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter | this user input | +| LdapInjection.java:230:14:230:33 | ... + ... | LdapInjection.java:229:57:229:83 | sBadDN : String | LdapInjection.java:230:14:230:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:229:57:229:83 | sBadDN | this user input | +| LdapInjection.java:230:36:230:55 | ... + ... | LdapInjection.java:229:30:229:54 | sBad : String | LdapInjection.java:230:36:230:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:229:30:229:54 | sBad | this user input | +| LdapInjection.java:235:20:235:85 | build(...) | LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | LdapInjection.java:235:20:235:85 | build(...) | LDAP query might include code from $@. | LdapInjection.java:234:57:234:92 | sBadDNLNBuilder | this user input | +| LdapInjection.java:235:88:235:107 | ... + ... | LdapInjection.java:234:30:234:54 | sBad : String | LdapInjection.java:235:88:235:107 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:234:30:234:54 | sBad | this user input | +| LdapInjection.java:240:23:240:97 | build(...) | LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:240:23:240:97 | build(...) | LDAP query might include code from $@. | LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd | this user input | +| LdapInjection.java:240:100:240:119 | ... + ... | LdapInjection.java:239:30:239:54 | sBad : String | LdapInjection.java:240:100:240:119 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:239:30:239:54 | sBad | this user input | +| LdapInjection.java:245:15:245:76 | filter(...) | LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | LdapInjection.java:245:15:245:76 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:244:30:244:63 | sBadLdapQuery | this user input | +| LdapInjection.java:250:12:250:63 | newLdapName(...) | LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | LdapInjection.java:250:12:250:63 | newLdapName(...) | LDAP query might include code from $@. | LdapInjection.java:249:63:249:98 | sBadDNLdapUtils | this user input | +| LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | LdapInjection.java:249:30:249:60 | sBadFilter : String | LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | LDAP query might include code from $@. | LdapInjection.java:249:30:249:60 | sBadFilter | this user input | +| LdapInjection.java:255:24:255:85 | filter(...) | LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | LdapInjection.java:255:24:255:85 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:254:30:254:63 | sBadLdapQuery | this user input | +| LdapInjection.java:261:24:261:24 | q | LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | LdapInjection.java:261:24:261:24 | q | LDAP query might include code from $@. | LdapInjection.java:259:30:259:64 | sBadLdapQuery2 | this user input | +| LdapInjection.java:266:24:266:116 | filter(...) | LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:266:24:266:116 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter | this user input | +| LdapInjection.java:272:24:272:57 | filter(...) | LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:272:24:272:57 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 | this user input | +| LdapInjection.java:277:12:277:66 | base(...) | LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | LdapInjection.java:277:12:277:66 | base(...) | LDAP query might include code from $@. | LdapInjection.java:276:31:276:68 | sBadLdapQueryBase | this user input | +| LdapInjection.java:282:24:282:98 | is(...) | LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | LdapInjection.java:282:24:282:98 | is(...) | LDAP query might include code from $@. | LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex | this user input | +| LdapInjection.java:287:18:287:83 | toString(...) | LdapInjection.java:286:31:286:69 | sBadFilterToString : String | LdapInjection.java:287:18:287:83 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:286:31:286:69 | sBadFilterToString | this user input | +| LdapInjection.java:294:18:294:29 | toString(...) | LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | LdapInjection.java:294:18:294:29 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:291:31:291:67 | sBadFilterEncode | this user input | +| LdapInjection.java:316:14:316:33 | ... + ... | LdapInjection.java:314:57:314:83 | aBadDN : String | LdapInjection.java:316:14:316:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:314:57:314:83 | aBadDN | this user input | +| LdapInjection.java:316:36:316:55 | ... + ... | LdapInjection.java:314:30:314:54 | aBad : String | LdapInjection.java:316:36:316:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:314:30:314:54 | aBad | this user input | +| LdapInjection.java:322:14:322:62 | getName(...) | LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | LdapInjection.java:322:14:322:62 | getName(...) | LDAP query might include code from $@. | LdapInjection.java:320:57:320:94 | aBadDNObjToString | this user input | +| LdapInjection.java:322:65:322:84 | ... + ... | LdapInjection.java:320:30:320:54 | aBad : String | LdapInjection.java:322:65:322:84 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:320:30:320:54 | aBad | this user input | +| LdapInjection.java:330:14:330:14 | s | LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | LdapInjection.java:330:14:330:14 | s | LDAP query might include code from $@. | LdapInjection.java:326:30:326:67 | aBadSearchRequest | this user input | +| LdapInjection.java:338:14:338:14 | s | LdapInjection.java:334:74:334:103 | aBadDNObj : String | LdapInjection.java:338:14:338:14 | s | LDAP query might include code from $@. | LdapInjection.java:334:74:334:103 | aBadDNObj | this user input | +| LdapInjection.java:346:14:346:24 | getBase(...) | LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | LdapInjection.java:346:14:346:24 | getBase(...) | LDAP query might include code from $@. | LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet | this user input | diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java index 5a5f7b238b4..7e585581f0b 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java @@ -34,35 +34,44 @@ import org.springframework.ldap.query.LdapQueryBuilder; import org.springframework.ldap.support.LdapEncoder; import org.springframework.ldap.support.LdapNameBuilder; import org.springframework.ldap.support.LdapUtils; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; +@Controller public class LdapInjection { // JNDI + @RequestMapping public void testJndiBad1(@RequestParam String jBad, @RequestParam String jBadDN, DirContext ctx) throws NamingException { ctx.search("ou=system" + jBadDN, "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad2(@RequestParam String jBad, @RequestParam String jBadDNName, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("ou=system" + jBadDNName), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad3(@RequestParam String jBad, @RequestParam String jOkDN, LdapContext ctx) throws NamingException { ctx.search(new LdapName(List.of(new Rdn("ou=" + jOkDN))), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad4(@RequestParam String jBadInitial, InitialLdapContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + jBadInitial + ")", new SearchControls()); } + @RequestMapping public void testJndiBad5(@RequestParam String jBad, @RequestParam String jBadDNNameAdd, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("").addAll(new LdapName("ou=system" + jBadDNNameAdd)), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad6(@RequestParam String jBad, @RequestParam String jBadDNNameAdd2, InitialDirContext ctx) throws NamingException { LdapName name = new LdapName(""); @@ -70,34 +79,41 @@ public class LdapInjection { ctx.search(new LdapName("").addAll(name), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad7(@RequestParam String jBad, @RequestParam String jBadDNNameToString, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("ou=system" + jBadDNNameToString).toString(), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad8(@RequestParam String jBad, @RequestParam String jBadDNNameClone, InitialDirContext ctx) throws NamingException { ctx.search((Name) new LdapName("ou=system" + jBadDNNameClone).clone(), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiOk1(@RequestParam String jOkFilterExpr, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid={0})", new String[] { jOkFilterExpr }, new SearchControls()); } + @RequestMapping public void testJndiOk2(@RequestParam String jOkAttribute, DirContext ctx) throws NamingException { ctx.search("ou=system", new BasicAttributes(jOkAttribute, jOkAttribute)); } // UnboundID + @RequestMapping public void testUnboundBad1(@RequestParam String uBad, @RequestParam String uBadDN, LDAPConnection c) throws LDAPSearchException { c.search(null, "ou=system" + uBadDN, null, null, 1, 1, false, "(uid=" + uBad + ")"); } + @RequestMapping public void testUnboundBad2(@RequestParam String uBadFilterCreate, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreate)); } + @RequestMapping public void testUnboundBad3(@RequestParam String uBadROSearchRequest, @RequestParam String uBadROSRDN, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDN, null, null, 1, 1, false, @@ -105,6 +121,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad4(@RequestParam String uBadSearchRequest, @RequestParam String uBadSRDN, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDN, null, null, 1, 1, false, @@ -112,11 +129,13 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad5(@RequestParam String uBad, @RequestParam String uBadDNSFR, LDAPConnection c) throws LDAPSearchException { c.searchForEntry("ou=system" + uBadDNSFR, null, null, 1, false, "(uid=" + uBad + ")"); } + @RequestMapping public void testUnboundBad6(@RequestParam String uBadROSearchRequestAsync, @RequestParam String uBadROSRDNAsync, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDNAsync, null, null, 1, 1, false, @@ -124,6 +143,7 @@ public class LdapInjection { c.asyncSearch(s); } + @RequestMapping public void testUnboundBad7(@RequestParam String uBadSearchRequestAsync, @RequestParam String uBadSRDNAsync, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDNAsync, null, null, 1, 1, false, @@ -131,20 +151,24 @@ public class LdapInjection { c.asyncSearch(s); } + @RequestMapping public void testUnboundBad8(@RequestParam String uBadFilterCreateNOT, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.createNOTFilter(Filter.create(uBadFilterCreateNOT))); } + @RequestMapping public void testUnboundBad9(@RequestParam String uBadFilterCreateToString, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreateToString).toString()); } + @RequestMapping public void testUnboundBad10(@RequestParam String uBadFilterCreateToStringBuffer, LDAPConnection c) throws LDAPException { StringBuilder b = new StringBuilder(); Filter.create(uBadFilterCreateToStringBuffer).toNormalizedString(b); c.search(null, "ou=system", null, null, 1, 1, false, b.toString()); } - + + @RequestMapping public void testUnboundBad11(@RequestParam String uBadSearchRequestDuplicate, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, @@ -152,6 +176,7 @@ public class LdapInjection { c.search(s.duplicate()); } + @RequestMapping public void testUnboundBad12(@RequestParam String uBadROSearchRequestDuplicate, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, @@ -159,6 +184,7 @@ public class LdapInjection { c.search(s.duplicate()); } + @RequestMapping public void testUnboundBad13(@RequestParam String uBadSearchRequestSetDN, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "", null, null, 1, 1, false, ""); @@ -166,6 +192,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad14(@RequestParam String uBadSearchRequestSetFilter, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, ""); @@ -173,20 +200,24 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundOk1(@RequestParam String uOkEqualityFilter, LDAPConnection c) throws LDAPSearchException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.createEqualityFilter("uid", uOkEqualityFilter)); } + @RequestMapping public void testUnboundOk2(@RequestParam String uOkVaragsAttr, LDAPConnection c) throws LDAPSearchException { c.search("ou=system", null, null, 1, 1, false, "(uid=fixed)", "a" + uOkVaragsAttr); } + @RequestMapping public void testUnboundOk3(@RequestParam String uOkFilterSearchRequest, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, Filter.createEqualityFilter("uid", uOkFilterSearchRequest)); c.search(s); } + @RequestMapping public void testUnboundOk4(@RequestParam String uOkSearchRequestVarargs, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest("ou=system", null, "(uid=fixed)", "va1", "va2", "va3", "a" + uOkSearchRequestVarargs); @@ -194,85 +225,104 @@ public class LdapInjection { } // Spring LDAP + @RequestMapping public void testSpringBad1(@RequestParam String sBad, @RequestParam String sBadDN, LdapTemplate c) { c.search("ou=system" + sBadDN, "(uid=" + sBad + ")", 1, false, null); } + @RequestMapping public void testSpringBad2(@RequestParam String sBad, @RequestParam String sBadDNLNBuilder, LdapTemplate c) { c.authenticate(LdapNameBuilder.newInstance("ou=system" + sBadDNLNBuilder).build(), "(uid=" + sBad + ")", "pass"); } + @RequestMapping public void testSpringBad3(@RequestParam String sBad, @RequestParam String sBadDNLNBuilderAdd, LdapTemplate c) { c.searchForObject(LdapNameBuilder.newInstance().add("ou=system" + sBadDNLNBuilderAdd).build(), "(uid=" + sBad + ")", null); } + @RequestMapping public void testSpringBad4(@RequestParam String sBadLdapQuery, LdapTemplate c) { c.findOne(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"), null); } + @RequestMapping public void testSpringBad5(@RequestParam String sBadFilter, @RequestParam String sBadDNLdapUtils, LdapTemplate c) { c.find(LdapUtils.newLdapName("ou=system" + sBadDNLdapUtils), new HardcodedFilter("(uid=" + sBadFilter + ")"), null, null); } + @RequestMapping public void testSpringBad6(@RequestParam String sBadLdapQuery, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")")); } + @RequestMapping public void testSpringBad7(@RequestParam String sBadLdapQuery2, LdapTemplate c) { LdapQuery q = LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery2 + ")"); c.searchForContext(q); } + @RequestMapping public void testSpringBad8(@RequestParam String sBadLdapQueryWithFilter, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().filter(new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter + ")"))); } + @RequestMapping public void testSpringBad9(@RequestParam String sBadLdapQueryWithFilter2, LdapTemplate c) { org.springframework.ldap.filter.Filter f = new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter2 + ")"); c.searchForContext(LdapQueryBuilder.query().filter(f)); } + @RequestMapping public void testSpringBad10(@RequestParam String sBadLdapQueryBase, LdapTemplate c) { c.find(LdapQueryBuilder.query().base(sBadLdapQueryBase).base(), null, null, null); } + @RequestMapping public void testSpringBad11(@RequestParam String sBadLdapQueryComplex, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().base(sBadLdapQueryComplex).where("uid").is("test")); } + @RequestMapping public void testSpringBad12(@RequestParam String sBadFilterToString, LdapTemplate c) { c.search("", new HardcodedFilter("(uid=" + sBadFilterToString + ")").toString(), 1, false, null); } + @RequestMapping public void testSpringBad13(@RequestParam String sBadFilterEncode, LdapTemplate c) { StringBuffer s = new StringBuffer(); new HardcodedFilter("(uid=" + sBadFilterEncode + ")").encode(s); c.search("", s.toString(), 1, false, null); } + @RequestMapping public void testSpringOk1(@RequestParam String sOkLdapQuery, LdapTemplate c) { c.find(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), null); } + @RequestMapping public void testSpringOk2(@RequestParam String sOkFilter, @RequestParam String sOkDN, LdapTemplate c) { c.find(LdapNameBuilder.newInstance().add("ou", sOkDN).build(), new EqualsFilter("uid", sOkFilter), null, null); } + @RequestMapping public void testSpringOk3(@RequestParam String sOkLdapQuery, @RequestParam String sOkPassword, LdapTemplate c) { c.authenticate(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), sOkPassword); } // Apache LDAP API + @RequestMapping public void testApacheBad1(@RequestParam String aBad, @RequestParam String aBadDN, LdapConnection c) throws LdapException { c.search("ou=system" + aBadDN, "(uid=" + aBad + ")", null); } + @RequestMapping public void testApacheBad2(@RequestParam String aBad, @RequestParam String aBadDNObjToString, LdapNetworkConnection c) throws LdapException { c.search(new Dn("ou=system" + aBadDNObjToString).getName(), "(uid=" + aBad + ")", null); } + @RequestMapping public void testApacheBad3(@RequestParam String aBadSearchRequest, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -280,6 +330,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheBad4(@RequestParam String aBadSearchRequestImpl, @RequestParam String aBadDNObj, LdapConnection c) throws LdapException { SearchRequestImpl s = new SearchRequestImpl(); @@ -287,6 +338,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheBad5(@RequestParam String aBadDNSearchRequestGet, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -294,6 +346,7 @@ public class LdapInjection { c.search(s.getBase(), "(uid=test", null); } + @RequestMapping public void testApacheOk1(@RequestParam String aOk, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -301,6 +354,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheOk2(@RequestParam String aOk, LdapConnection c) throws LdapException { SearchRequestImpl s = new SearchRequestImpl(); @@ -309,17 +363,20 @@ public class LdapInjection { } // ESAPI encoder sanitizer + @RequestMapping public void testOk3(@RequestParam String okEncodeForLDAP, DirContext ctx) throws NamingException { Encoder encoder = DefaultEncoder.getInstance(); ctx.search("ou=system", "(uid=" + encoder.encodeForLDAP(okEncodeForLDAP) + ")", new SearchControls()); } // Spring LdapEncoder sanitizer + @RequestMapping public void testOk4(@RequestParam String okFilterEncode, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + LdapEncoder.filterEncode(okFilterEncode) + ")", new SearchControls()); } // UnboundID Filter.encodeValue sanitizer + @RequestMapping public void testOk5(@RequestParam String okUnboundEncodeValue, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + Filter.encodeValue(okUnboundEncodeValue) + ")", new SearchControls()); } diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java new file mode 100644 index 00000000000..4a853250618 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java @@ -0,0 +1,10 @@ +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.BasicAWSCredentials; + +public class HardcodedAWSCredentials { + public static void main(String[] args) { + //BAD: Hardcoded credentials for connecting to AWS services + //To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead + AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); + } +} \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index 79e99b55479..ccd0259322e 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -40,6 +40,8 @@ nodes | FileCredentialTest.java:19:13:19:13 | u : String | semmle.label | u : String | | FileCredentialTest.java:22:38:22:45 | v : String | semmle.label | v : String | | FileCredentialTest.java:23:36:23:36 | v | semmle.label | v | +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | semmle.label | "ACCESS_KEY" | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | semmle.label | "SECRET_KEY" | | Test.java:9:16:9:22 | "admin" : String | semmle.label | "admin" : String | | Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | | Test.java:12:13:12:15 | usr : String | semmle.label | usr : String | @@ -68,6 +70,8 @@ nodes | CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:18:36:18:36 | v | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | | FileCredentialTest.java:13:14:13:20 | "admin" | FileCredentialTest.java:13:14:13:20 | "admin" : String | FileCredentialTest.java:23:36:23:36 | v | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | sensitive API call | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/options b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options new file mode 100644 index 00000000000..e13da5319f0 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700 diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt new file mode 100644 index 00000000000..22d244f8c3a --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt @@ -0,0 +1,53 @@ +Apache License +Version 2.0, January 2004 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Note: Other license terms may apply to certain, identified software files contained within or distributed with the accompanying software if such terms are included in the directory containing the accompanying software. Such other license terms will then apply in lieu of the terms of the software license above. diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java new file mode 100644 index 00000000000..147660835c2 --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.amazonaws.auth; + +/** + * Provides access to the AWS credentials used for accessing AWS services: AWS + * access key ID and secret access key. These credentials are used to securely + * sign requests to AWS services. + *

    + * A basic implementation of this interface is provided in + * {@link BasicAWSCredentials}, but callers are free to provide their own + * implementation, for example, to load AWS credentials from an encrypted file. + *

    + * For more details on AWS access keys, see: http://docs.amazonwebservices.com/AWSSecurityCredentials/1.0/ + * AboutAWSCredentials.html#AccessKeys + */ +public interface AWSCredentials { + + /** + * Returns the AWS access key ID for this credentials object. + * + * @return The AWS access key ID for this credentials object. + */ + public String getAWSAccessKeyId(); + + /** + * Returns the AWS secret access key for this credentials object. + * + * @return The AWS secret access key for this credentials object. + */ + public String getAWSSecretKey(); + +} diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java new file mode 100644 index 00000000000..dc9f67a90d4 --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.amazonaws.auth; + +/** + * Basic implementation of the AWSCredentials interface that allows callers to + * pass in the AWS access key and secret access in the constructor. + */ +public class BasicAWSCredentials implements AWSCredentials { + + /** + * Constructs a new BasicAWSCredentials object, with the specified AWS + * access key and AWS secret key. + * + * @param accessKey + * The AWS access key. + * @param secretKey + * The AWS secret access key. + */ + public BasicAWSCredentials(String accessKey, String secretKey) { + } + + /* (non-Javadoc) + * @see com.amazonaws.auth.AWSCredentials#getAWSAccessKeyId() + */ + public String getAWSAccessKeyId() { + return null; + } + + /* (non-Javadoc) + * @see com.amazonaws.auth.AWSCredentials#getAWSSecretKey() + */ + public String getAWSSecretKey() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt b/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java new file mode 100644 index 00000000000..5024bf1c462 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Defines common decoding methods for byte array decoders. + * + */ +public interface BinaryDecoder extends Decoder { + + /** + * Decodes a byte array and returns the results as a byte array. + * + * @param source + * A byte array which has been encoded with the appropriate encoder + * @return a byte array that contains decoded content + * @throws DecoderException + * A decoder exception is thrown if a Decoder encounters a failure condition during the decode process. + */ + byte[] decode(byte[] source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java new file mode 100644 index 00000000000..6803f0c5859 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Defines common encoding methods for byte array encoders. + * + */ +public interface BinaryEncoder extends Encoder { + + /** + * Encodes a byte array and return the encoded data as a byte array. + * + * @param source + * Data to be encoded + * @return A byte array containing the encoded data + * @throws EncoderException + * thrown if the Encoder encounters a failure condition during the encoding process. + */ + byte[] encode(byte[] source) throws EncoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java new file mode 100644 index 00000000000..3214bf6f56e --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Provides the highest level of abstraction for Decoders. + *

    + * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface. + * Allows a user to pass a generic Object to any Decoder implementation in the codec package. + *

    + * One of the two interfaces at the center of the codec package. + * + */ +public interface Decoder { + + /** + * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will + * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a + * {@link ClassCastException} occurs this decode method will throw a DecoderException. + * + * @param source + * the object to decode + * @return a 'decoded" object + * @throws DecoderException + * a decoder exception can be thrown for any number of reasons. Some good candidates are that the + * parameter passed to this method is null, a param cannot be cast to the appropriate type for a + * specific encoder. + */ + Object decode(Object source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java new file mode 100644 index 00000000000..c8fac4195f7 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder} + * encounters a decoding specific exception such as invalid data, or characters outside of the expected range. + * + */ +public class DecoderException extends Exception { + + /** + * Declares the Serial Version Uid. + * + * @see Always Declare Serial Version Uid + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link #initCause}. + * + * @since 1.4 + */ + public DecoderException() { + super(); + } + + /** + * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause}. + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + */ + public DecoderException(final String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + *

    + * Note that the detail message associated with {@code cause} is not automatically incorporated into this + * exception's detail message. + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public DecoderException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail message of (cause==null ? + * null : cause.toString()) (which typically contains the class and detail message of {@code cause}). + * This constructor is useful for exceptions that are little more than wrappers for other throwables. + * + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public DecoderException(final Throwable cause) { + super(cause); + } +} diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java new file mode 100644 index 00000000000..18168ecdee6 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Provides the highest level of abstraction for Encoders. + *

    + * This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this + * common generic interface which allows a user to pass a generic Object to any Encoder implementation + * in the codec package. + * + */ +public interface Encoder { + + /** + * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be + * {@code byte[]} or {@code String}s depending on the implementation used. + * + * @param source + * An object to encode + * @return An "encoded" Object + * @throws EncoderException + * An encoder exception is thrown if the encoder experiences a failure condition during the encoding + * process. + */ + Object encode(Object source) throws EncoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java new file mode 100644 index 00000000000..070e8966f6a --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Thrown when there is a failure condition during the encoding process. This exception is thrown when an + * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum, + * characters outside of the expected range. + * + */ +public class EncoderException extends Exception { + + /** + * Declares the Serial Version Uid. + * + * @see Always Declare Serial Version Uid + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link #initCause}. + * + * @since 1.4 + */ + public EncoderException() { + super(); + } + + /** + * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause}. + * + * @param message + * a useful message relating to the encoder specific error. + */ + public EncoderException(final String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *

    + * Note that the detail message associated with {@code cause} is not automatically incorporated into this + * exception's detail message. + *

    + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public EncoderException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail message of (cause==null ? + * null : cause.toString()) (which typically contains the class and detail message of {@code cause}). + * This constructor is useful for exceptions that are little more than wrappers for other throwables. + * + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public EncoderException(final Throwable cause) { + super(cause); + } +} diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java new file mode 100644 index 00000000000..0c041e3e0ad --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Defines common decoding methods for String decoders. + * + */ +public interface StringDecoder extends Decoder { + + /** + * Decodes a String and returns a String. + * + * @param source + * the String to decode + * @return the encoded String + * @throws DecoderException + * thrown if there is an error condition during the Encoding process. + */ + String decode(String source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java new file mode 100644 index 00000000000..9e445d3b1ef --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.codec; + +/** + * Defines common encoding methods for String encoders. + * + */ +public interface StringEncoder extends Encoder { + + /** + * Encodes a String and returns a String. + * + * @param source + * the String to encode + * @return the encoded String + * @throws EncoderException + * thrown if there is an error condition during the encoding process. + */ + String encode(String source) throws EncoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt b/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java new file mode 100644 index 00000000000..9802c1be2c1 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.mail; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +/** + * This is a very simple authentication object that can be used for any + * transport needing basic userName and password type authentication. + * + * @since 1.0 + */ +public class DefaultAuthenticator extends Authenticator +{ + /** Stores the login information for authentication. */ + private final PasswordAuthentication authentication; + + /** + * Default constructor. + * + * @param userName user name to use when authentication is requested + * @param password password to use when authentication is requested + * @since 1.0 + */ + public DefaultAuthenticator(final String userName, final String password) + { + this.authentication = new PasswordAuthentication(userName, password); + } + + /** + * Gets the authentication object that will be used to login to the mail + * server. + * + * @return A {@code PasswordAuthentication} object containing the + * login information. + * @since 1.0 + */ + @Override + protected PasswordAuthentication getPasswordAuthentication() + { + return this.authentication; + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java new file mode 100644 index 00000000000..4fbef7c0e2e --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java @@ -0,0 +1,805 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.mail; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.mail.Authenticator; + +/** + * The base class for all email messages. This class sets the sender's email + * & name, receiver's email & name, subject, and the sent date. + *

    + * Subclasses are responsible for setting the message body. + * + * @since 1.0 + */ +public abstract class Email { + /** + * Sets the userName and password if authentication is needed. If this method is + * not used, no authentication will be performed. + *

    + * This method will create a new instance of {@code DefaultAuthenticator} using + * the supplied parameters. + * + * @param userName User name for the SMTP server + * @param password password for the SMTP server + * @see DefaultAuthenticator + * @see #setAuthenticator + * @since 1.0 + */ + public void setAuthentication(final String userName, final String password) { + } + + /** + * Sets the {@code Authenticator} to be used when authentication is requested + * from the mail server. + *

    + * This method should be used when your outgoing mail server requires + * authentication. Your mail server must also support RFC2554. + * + * @param newAuthenticator the {@code Authenticator} object. + * @see Authenticator + * @since 1.0 + */ + public void setAuthenticator(final Authenticator newAuthenticator) { + } + + /** + * Set the hostname of the outgoing mail server. + * + * @param aHostName aHostName + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + */ + public void setHostName(final String aHostName) { + } + + /** + * Set or disable the STARTTLS encryption. Please see EMAIL-105 for the reasons + * of deprecation. + * + * @deprecated since 1.3, use setStartTLSEnabled() instead + * @param withTLS true if STARTTLS requested, false otherwise + * @since 1.1 + */ + @Deprecated + public void setTLS(final boolean withTLS) { + } + + /** + * Set or disable the STARTTLS encryption. + * + * @param startTlsEnabled true if STARTTLS requested, false otherwise + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setStartTLSEnabled(final boolean startTlsEnabled) { + return null; + } + + /** + * Set or disable the required STARTTLS encryption. + *

    + * Defaults to {@link #smtpPort}; can be overridden by using + * {@link #setSmtpPort(int)} + * + * @param startTlsRequired true if STARTTLS requested, false otherwise + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setStartTLSRequired(final boolean startTlsRequired) { + return null; + } + + /** + * Set the non-SSL port number of the outgoing mail server. + * + * @param aPortNumber aPortNumber + * @throws IllegalArgumentException if the port number is < 1 + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + * @see #setSslSmtpPort(String) + */ + public void setSmtpPort(final int aPortNumber) { + } + + /** + * Set the FROM field of the email to use the specified address. The email + * address will also be used as the personal name. The name will be encoded by + * the charset of {@link #setCharset(java.lang.String) setCharset()}. If it is + * not set, it will be encoded using the Java platform's default charset + * (UTF-16) if it contains non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email setFrom(final String email) throws EmailException { + return null; + } + + /** + * Set the FROM field of the email to use the specified address and the + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email setFrom(final String email, final String name) throws EmailException { + return null; + } + + /** + * Set the FROM field of the email to use the specified address, personal name, + * and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email setFrom(final String email, final String name, final String charset) throws EmailException { + return null; + } + + /** + * Add a recipient TO to the email. The email address will also be used as the + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addTo(final String email) throws EmailException { + return null; + } + + /** + * Add a list of TO recipients to the email. The email addresses will also be + * used as the personal names. The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.3 + */ + public Email addTo(final String... emails) throws EmailException { + return null; + } + + /** + * Add a recipient TO to the email using the specified address and the specified + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addTo(final String email, final String name) throws EmailException { + return null; + } + + /** + * Add a recipient TO to the email using the specified address, personal name, + * and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addTo(final String email, final String name, final String charset) throws EmailException { + return null; + } + + /** + * Add a recipient CC to the email. The email address will also be used as the + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addCc(final String email) throws EmailException { + return null; + } + + /** + * Add an array of CC recipients to the email. The email addresses will also be + * used as the personal name. The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.3 + */ + public Email addCc(final String... emails) throws EmailException { + return null; + } + + /** + * Add a recipient CC to the email using the specified address and the specified + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addCc(final String email, final String name) throws EmailException { + return null; + } + + /** + * Add a recipient CC to the email using the specified address, personal name, + * and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addCc(final String email, final String name, final String charset) throws EmailException { + return null; + } + + /** + * Add a blind BCC recipient to the email. The email address will also be used + * as the personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addBcc(final String email) throws EmailException { + return null; + } + + /** + * Add an array of blind BCC recipients to the email. The email addresses will + * also be used as the personal name. The names will be encoded by the charset + * of {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it + * will be encoded using the Java platform's default charset (UTF-16) if it + * contains non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.3 + */ + public Email addBcc(final String... emails) throws EmailException { + return null; + } + + /** + * Add a blind BCC recipient to the email using the specified address and the + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addBcc(final String email, final String name) throws EmailException { + return null; + } + + /** + * Add a blind BCC recipient to the email using the specified address, personal + * name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.1 + */ + public Email addBcc(final String email, final String name, final String charset) throws EmailException { + return null; + } + + /** + * Add a reply to address to the email. The email address will also be used as + * the personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addReplyTo(final String email) throws EmailException { + return null; + } + + /** + * Add a reply to address to the email using the specified address and the + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addReplyTo(final String email, final String name) throws EmailException { + return null; + } + + /** + * Add a reply to address to the email using the specified address, personal + * name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addReplyTo(final String email, final String name, final String charset) throws EmailException { + return null; + } + + /** + * Used to specify the mail headers. Example: + * + * X-Mailer: Sendmail, X-Priority: 1( highest ) or 2( high ) 3( normal ) 4( low + * ) and 5( lowest ) Disposition-Notification-To: user@domain.net + * + * @param map A Map. + * @throws IllegalArgumentException if either of the provided header / value is + * null or empty + * @since 1.0 + */ + public void setHeaders(final Map map) { + } + + /** + * Adds a header ( name, value ) to the headers Map. + * + * @param name A String with the name. + * @param value A String with the value. + * @since 1.0 + * @throws IllegalArgumentException if either {@code name} or {@code value} is + * null or empty + */ + public void addHeader(final String name, final String value) { + } + + /** + * Gets the specified header. + * + * @param header A string with the header. + * @return The value of the header, or null if no such header. + * @since 1.5 + */ + public String getHeader(final String header) { + return null; + } + + /** + * Gets all headers on an Email. + * + * @return a Map of all headers. + * @since 1.5 + */ + public Map getHeaders() { + return null; + } + + /** + * Sets the email subject. Replaces end-of-line characters with spaces. + * + * @param aSubject A String. + * @return An Email. + * @since 1.0 + */ + public Email setSubject(final String aSubject) { + return null; + } + + /** + * Gets the "bounce address" of this email. + * + * @return the bounce address as string + * @since 1.4 + */ + public String getBounceAddress() { + return null; + } + + /** + * Set the "bounce address" - the address to which undeliverable messages will + * be returned. If this value is never set, then the message will be sent to the + * address specified with the System property "mail.smtp.from", or if that value + * is not set, then to the "from" address. + * + * @param email A String. + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + */ + public Email setBounceAddress(final String email) { + return null; + } + + /** + * Define the content of the mail. It should be overridden by the subclasses. + * + * @param msg A String. + * @return An Email. + * @throws EmailException generic exception. + * @since 1.0 + */ + public abstract Email setMsg(String msg) throws EmailException; + + /** + * Does the work of actually building the MimeMessage. Please note that a user + * rarely calls this method directly and only if he/she is interested in the + * sending the underlying MimeMessage without commons-email. + * + * @throws IllegalStateException if the MimeMessage was already built + * @throws EmailException if there was an error. + * @since 1.0 + */ + public void buildMimeMessage() throws EmailException { + } + + /** + * Sends the previously created MimeMessage to the SMTP server. + * + * @return the message id of the underlying MimeMessage + * @throws IllegalArgumentException if the MimeMessage has not been created + * @throws EmailException the sending failed + */ + public String sendMimeMessage() throws EmailException { + return null; + } + + /** + * Sends the email. Internally we build a MimeMessage which is afterwards sent + * to the SMTP server. + * + * @return the message id of the underlying MimeMessage + * @throws IllegalStateException if the MimeMessage was already built, ie + * {@link #buildMimeMessage()} was already called + * @throws EmailException the sending failed + */ + public String send() throws EmailException { + return null; + } + + /** + * Sets the sent date for the email. The sent date will default to the current + * date if not explicitly set. + * + * @param date Date to use as the sent date on the email + * @since 1.0 + */ + public void setSentDate(final Date date) { + } + + /** + * Gets the sent date for the email. + * + * @return date to be used as the sent date for the email + * @since 1.0 + */ + public Date getSentDate() { + return null; + } + + /** + * Gets the subject of the email. + * + * @return email subject + */ + public String getSubject() { + return null; + } + + /** + * Gets the host name of the SMTP server, + * + * @return host name + */ + public String getHostName() { + return null; + } + + /** + * Gets the listening port of the SMTP server. + * + * @return smtp port + */ + public String getSmtpPort() { + return null; + } + + /** + * Gets whether the client is configured to require STARTTLS. + * + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.3 + */ + public boolean isStartTLSRequired() { + return false; + } + + /** + * Gets whether the client is configured to try to enable STARTTLS. + * + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.3 + */ + public boolean isStartTLSEnabled() { + return false; + } + + /** + * Gets whether the client is configured to try to enable STARTTLS. See + * EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use isStartTLSEnabled() instead + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.1 + */ + @Deprecated + public boolean isTLS() { + return false; + } + + /** + * Set details regarding "pop3 before smtp" authentication. + * + * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending + * mail. + * @param newPopHost The pop3 host to use. + * @param newPopUsername The pop3 username. + * @param newPopPassword The pop3 password. + * @since 1.0 + */ + public void setPopBeforeSmtp(final boolean newPopBeforeSmtp, final String newPopHost, final String newPopUsername, + final String newPopPassword) { + } + + /** + * Returns whether SSL/TLS encryption for the transport is currently enabled + * (SMTPS/POPS). See EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use isSSLOnConnect() instead + * @return true if SSL enabled for the transport + */ + @Deprecated + public boolean isSSL() { + return false; + } + + /** + * Returns whether SSL/TLS encryption for the transport is currently enabled + * (SMTPS/POPS). + * + * @return true if SSL enabled for the transport + * @since 1.3 + */ + public boolean isSSLOnConnect() { + return false; + } + + /** + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon + * connection (SMTPS/POPS). See EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use setSSLOnConnect() instead + * @param ssl whether to enable the SSL transport + */ + @Deprecated + public void setSSL(final boolean ssl) { + } + + /** + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon + * connection (SMTPS/POPS). Takes precedence over + * {@link #setStartTLSRequired(boolean)} + *

    + * Defaults to {@link #sslSmtpPort}; can be overridden by using + * {@link #setSslSmtpPort(String)} + * + * @param ssl whether to enable the SSL transport + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setSSLOnConnect(final boolean ssl) { + return null; + } + + /** + * Is the server identity checked as specified by RFC 2595 + * + * @return true if the server identity is checked + * @since 1.3 + */ + public boolean isSSLCheckServerIdentity() { + return false; + } + + /** + * Sets whether the server identity is checked as specified by RFC 2595 + * + * @param sslCheckServerIdentity whether to enable server identity check + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) { + return null; + } + + /** + * Returns the current SSL port used by the SMTP transport. + * + * @return the current SSL port used by the SMTP transport + */ + public String getSslSmtpPort() { + return null; + } + + /** + * Sets the SSL port to use for the SMTP transport. Defaults to the standard + * port, 465. + * + * @param sslSmtpPort the SSL port to use for the SMTP transport + * @throws IllegalStateException if the mail session is already initialized + * @see #setSmtpPort(int) + */ + public void setSslSmtpPort(final String sslSmtpPort) { + } + + /** + * If partial sending of email enabled. + * + * @return true if sending partial email is enabled + * @since 1.3.2 + */ + public boolean isSendPartial() { + return false; + } + + /** + * Sets whether the email is partially send in case of invalid addresses. + *

    + * In case the mail server rejects an address as invalid, the call to + * {@link #send()} may throw a {@link javax.mail.SendFailedException}, even if + * partial send mode is enabled (emails to valid addresses will be transmitted). + * In case the email server does not reject invalid addresses immediately, but + * return a bounce message, no exception will be thrown by the {@link #send()} + * method. + * + * @param sendPartial whether to enable partial send mode + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3.2 + */ + public Email setSendPartial(final boolean sendPartial) { + return null; + } + + /** + * Get the socket connection timeout value in milliseconds. + * + * @return the timeout in milliseconds. + * @since 1.2 + */ + public int getSocketConnectionTimeout() { + return -1; + } + + /** + * Set the socket connection timeout value in milliseconds. Default is a 60 + * second timeout. + * + * @param socketConnectionTimeout the connection timeout + * @throws IllegalStateException if the mail session is already initialized + * @since 1.2 + */ + public void setSocketConnectionTimeout(final int socketConnectionTimeout) { + } + + /** + * Get the socket I/O timeout value in milliseconds. + * + * @return the socket I/O timeout + * @since 1.2 + */ + public int getSocketTimeout() { + return -1; + } + + /** + * Set the socket I/O timeout value in milliseconds. Default is 60 second + * timeout. + * + * @param socketTimeout the socket I/O timeout + * @throws IllegalStateException if the mail session is already initialized + * @since 1.2 + */ + public void setSocketTimeout(final int socketTimeout) { + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java new file mode 100644 index 00000000000..9fb067e9ffe --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.mail; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * Exception thrown when a checked error occurs in commons-email. + *

    + * Adapted from FunctorException in Commons Collections. + *

    + * Emulation support for nested exceptions has been removed in + * {@code Email 1.3}, supported by JDK ≥ 1.4. + * + * @since 1.0 + */ +public class EmailException extends Exception { + /** + * Constructs a new {@code EmailException} with no detail message. + */ + public EmailException() { + super(); + } + + /** + * Constructs a new {@code EmailException} with specified detail message. + * + * @param msg the error message. + */ + public EmailException(final String msg) { + super(msg); + } + + /** + * Constructs a new {@code EmailException} with specified nested + * {@code Throwable} root cause. + * + * @param rootCause the exception or error that caused this exception to be + * thrown. + */ + public EmailException(final Throwable rootCause) { + super(rootCause); + } + + /** + * Constructs a new {@code EmailException} with specified detail message and + * nested {@code Throwable} root cause. + * + * @param msg the error message. + * @param rootCause the exception or error that caused this exception to be + * thrown. + */ + public EmailException(final String msg, final Throwable rootCause) { + super(msg, rootCause); + } + + /** + * Prints the stack trace of this exception to the standard error stream. + */ + @Override + public void printStackTrace() { + printStackTrace(System.err); + } + + /** + * Prints the stack trace of this exception to the specified stream. + * + * @param out the {@code PrintStream} to use for output + */ + @Override + public void printStackTrace(final PrintStream out) { + } + + /** + * Prints the stack trace of this exception to the specified writer. + * + * @param out the {@code PrintWriter} to use for output + */ + @Override + public void printStackTrace(final PrintWriter out) { + synchronized (out) { + super.printStackTrace(out); + } + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java new file mode 100644 index 00000000000..9a01b8539b1 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.mail; + +/** + * This class is used to send simple internet email messages without + * attachments. + * + * @since 1.0 +*/ +public class SimpleEmail extends Email +{ + /** + * Set the content of the mail. + * + * @param msg A String. + * @return An Email. + * @throws EmailException see javax.mail.internet.MimeBodyPart + * for definitions + * @since 1.0 + */ + @Override + public Email setMsg(final String msg) throws EmailException + { + return null; + } +} diff --git a/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt b/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt new file mode 100644 index 00000000000..5ad62c442b3 --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt @@ -0,0 +1,759 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 + +1. Definitions. + + 1.1. "Contributor" means each individual or entity that creates or + contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Software, prior Modifications used by a Contributor (if any), and + the Modifications made by that particular Contributor. + + 1.3. "Covered Software" means (a) the Original Software, or (b) + Modifications, or (c) the combination of files containing Original + Software with files containing Modifications, in each case including + portions thereof. + + 1.4. "Executable" means the Covered Software in any form other than + Source Code. + + 1.5. "Initial Developer" means the individual or entity that first + makes Original Software available under this License. + + 1.6. "Larger Work" means a work which combines Covered Software or + portions thereof with code not governed by the terms of this License. + + 1.7. "License" means this document. + + 1.8. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means the Source Code and Executable form of + any of the following: + + A. Any file that results from an addition to, deletion from or + modification of the contents of a file containing Original Software + or previous Modifications; + + B. Any new file that contains any part of the Original Software or + previous Modification; or + + C. Any new file that is contributed or otherwise made available + under the terms of this License. + + 1.10. "Original Software" means the Source Code and Executable form + of computer software code that is originally released under this + License. + + 1.11. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.12. "Source Code" means (a) the common form of computer software + code in which modifications are made and (b) associated + documentation included in or with such code. + + 1.13. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, + this License. For legal entities, "You" includes any entity which + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject + to third party intellectual property claims, the Initial Developer + hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer, to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Software (or portions thereof), with or without Modifications, + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of + Original Software, to make, have made, use, practice, sell, and + offer for sale, and/or otherwise dispose of the Original Software + (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on + the date Initial Developer first distributes or otherwise makes the + Original Software available to a third party under the terms of this + License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: (1) for code that You delete from the Original Software, or + (2) for infringements caused by: (i) the modification of the + Original Software, or (ii) the combination of the Original Software + with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject + to third party intellectual property claims, each Contributor hereby + grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof), either on an + unmodified basis, with other Modifications, as Covered Software + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling + of Modifications made by that Contributor either alone and/or in + combination with its Contributor Version (or portions of such + combination), to make, use, sell, offer for sale, have made, and/or + otherwise dispose of: (1) Modifications made by that Contributor (or + portions thereof); and (2) the combination of Modifications made by + that Contributor with its Contributor Version (or portions of such + combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective + on the date Contributor first distributes or otherwise makes the + Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: (1) for any code that Contributor has deleted from the + Contributor Version; (2) for infringements caused by: (i) third + party modifications of Contributor Version, or (ii) the combination + of Modifications made by that Contributor with other software + (except as part of the Contributor Version) or other devices; or (3) + under Patent Claims infringed by Covered Software in the absence of + Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available + in Executable form must also be made available in Source Code form + and that Source Code form must be distributed only under the terms + of this License. You must include a copy of this License with every + copy of the Source Code form of the Covered Software You distribute + or otherwise make available. You must inform recipients of any such + Covered Software in Executable form as to how they can obtain such + Covered Software in Source Code form in a reasonable manner on or + through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are + governed by the terms of this License. You represent that You + believe Your Modifications are Your original creation(s) and/or You + have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that + identifies You as the Contributor of the Modification. You may not + remove or alter any copyright, patent or trademark notices contained + within the Covered Software, or any notices of licensing or any + descriptive text giving attribution to any Contributor or the + Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in + Source Code form that alters or restricts the applicable version of + this License or the recipients' rights hereunder. You may choose to + offer, and to charge a fee for, warranty, support, indemnity or + liability obligations to one or more recipients of Covered Software. + However, you may do so only on Your own behalf, and not on behalf of + the Initial Developer or any Contributor. You must make it + absolutely clear that any such warranty, support, indemnity or + liability obligation is offered by You alone, and You hereby agree + to indemnify the Initial Developer and every Contributor for any + liability incurred by the Initial Developer or such Contributor as a + result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under + the terms of this License or under the terms of a license of Your + choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable form does not attempt to + limit or alter the recipient's rights in the Source Code form from + the rights set forth in this License. If You distribute the Covered + Software in Executable form under a different license, You must make + it absolutely clear that any terms which differ from this License + are offered by You alone, not by the Initial Developer or + Contributor. You hereby agree to indemnify the Initial Developer and + every Contributor for any liability incurred by the Initial + Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with + other code not governed by the terms of this License and distribute + the Larger Work as a single product. In such a case, You must make + sure the requirements of this License are fulfilled for the Covered + Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or + new versions of this License from time to time. Each version will be + given a distinguishing version number. Except as provided in Section + 4.3, no one other than the license steward has the right to modify + this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the + Covered Software available under the terms of the version of the + License under which You originally received the Covered Software. If + the Initial Developer includes a notice in the Original Software + prohibiting it from being distributed or otherwise made available + under any subsequent version of the License, You must distribute and + make the Covered Software available under the terms of the version + of the License under which You originally received the Covered + Software. Otherwise, You may also choose to use, distribute or + otherwise make the Covered Software available under the terms of any + subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new + license for Your Original Software, You may create and use a + modified version of this License if You: (a) rename the license and + remove any references to the name of the license steward (except to + note that the license differs from this License); and (b) otherwise + make it clear that the license contains terms which differ from this + License. + +5. DISCLAIMER OF WARRANTY. + + COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE + IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR + NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF + THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE + DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY + OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, + REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN + ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS + AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to + cure such breach within 30 days of becoming aware of the breach. + Provisions which, by their nature, must remain in effect beyond the + termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding + declaratory judgment actions) against Initial Developer or a + Contributor (the Initial Developer or Contributor against whom You + assert such claim is referred to as "Participant") alleging that the + Participant Software (meaning the Contributor Version where the + Participant is a Contributor or the Original Software where the + Participant is the Initial Developer) directly or indirectly + infringes any patent, then any and all rights granted directly or + indirectly to You by such Participant, the Initial Developer (if the + Initial Developer is not the Participant) and all Contributors under + Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice + from Participant terminate prospectively and automatically at the + expiration of such 60 day notice period, unless if within such 60 + day period You withdraw Your claim with respect to the Participant + Software against such Participant either unilaterally or pursuant to + a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant + alleging that the Participant Software directly or indirectly + infringes any patent where such claim is resolved (such as by + license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, + all end user licenses that have been validly granted by You or any + distributor hereunder prior to termination (excluding licenses + granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE + INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF + COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE + TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER + FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR + LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE + POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT + APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH + PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH + LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR + LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION + AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + + The Covered Software is a "commercial item," as that term is defined + in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" (as that term is defined at 48 C.F.R. + 252.227-7014(a)(1)) and "commercial computer software documentation" + as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent + with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 + (June 1995), all U.S. Government End Users acquire Covered Software + with only those rights set forth herein. This U.S. Government Rights + clause is in lieu of, and supersedes, any other FAR, DFAR, or other + clause or provision that addresses Government rights in computer + software under this License. + +9. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + the law of the jurisdiction specified in a notice contained within + the Original Software (except to the extent applicable law, if any, + provides otherwise), excluding such jurisdiction's conflict-of-law + provisions. Any litigation relating to this License shall be subject + to the jurisdiction of the courts located in the jurisdiction and + venue specified in a notice contained within the Original Software, + with the losing party responsible for costs, including, without + limitation, court costs and reasonable attorneys' fees and expenses. + The application of the United Nations Convention on Contracts for + the International Sale of Goods is expressly excluded. Any law or + regulation which provides that the language of a contract shall be + construed against the drafter shall not apply to this License. You + agree that You alone are responsible for compliance with the United + States export administration regulations (and the export control + laws and regulation of any other countries) when You use, distribute + or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +------------------------------------------------------------------------ + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION +LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the +State of California (excluding conflict-of-law provisions). Any +litigation relating to this License shall be subject to the jurisdiction +of the Federal Courts of the Northern District of California and the +state courts of the State of California, with venue lying in Santa Clara +County, California. + + + + The GNU General Public License (GPL) Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor +Boston, MA 02110-1335 +USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. This General Public +License applies to most of the Free Software Foundation's software and +to any other program whose authors commit to using it. (Some other Free +Software Foundation software is covered by the GNU Library General +Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. +Our General Public Licenses are designed to make sure that you have the +freedom to distribute copies of free software (and charge for this +service if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis +or for a fee, you must give the recipients all the rights that you have. +You must make sure that they, too, receive or can get the source code. +And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent must +be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed under +the terms of this General Public License. The "Program", below, refers +to any such program or work, and a "work based on the Program" means +either the Program or any derivative work under copyright law: that is +to say, a work containing the Program or a portion of it, either +verbatim or with modifications and/or translated into another language. +(Hereinafter, translation is included without limitation in the term +"modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +the Program is not restricted, and the output from the Program is +covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any part + thereof, to be licensed as a whole at no charge to all third parties + under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this License. + (Exception: if the Program itself is interactive but does not + normally print such an announcement, your work based on the Program + is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, and +can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based on +the Program, the distribution of the whole must be on the terms of this +License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of a +storage or distribution medium does not bring the other work under the +scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your cost + of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed + only for noncommercial distribution and only if you received the + program in object code or executable form with such an offer, in + accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source code +means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies the +executable. + +If distribution of executable or object code is made by offering access +to copy from a designated place, then offering equivalent access to copy +the source code from the same place counts as distribution of the source +code, even though third parties are not compelled to copy the source +along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will +not have their licenses terminated so long as such parties remain in +full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and all +its terms and conditions for copying, distributing or modifying the +Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further restrictions +on the recipients' exercise of the rights granted herein. You are not +responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License and +any other pertinent obligations, then as a consequence you may not +distribute the Program at all. For example, if a patent license would +not permit royalty-free redistribution of the Program by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up to +the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be +a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a version +number of this License, you may choose any version ever published by the +Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH +YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type + `show w'. This is free software, and you are welcome to redistribute + it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the commands +you use may be called something other than `show w' and `show c'; they +could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (which makes passes at compilers) written by + James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications +with the library. If this is what you want to do, use the GNU Library +General Public License instead of this License. + +# + +Certain source files distributed by Oracle America, Inc. and/or its +affiliates are subject to the following clarification and special +exception to the GPLv2, based on the GNU Project exception for its +Classpath libraries, known as the GNU Classpath Exception, but only +where Oracle has expressly included in the particular source file's +header the words "Oracle designates this particular file as subject to +the "Classpath" exception as provided by Oracle in the LICENSE file +that accompanied this code." + +You should also note that Oracle includes multiple, independent +programs in this software package. Some of those programs are provided +under licenses deemed incompatible with the GPLv2 by the Free Software +Foundation and others. For example, the package includes programs +licensed under the Apache License, Version 2.0. Such programs are +licensed to you under their original licenses. + +Oracle facilitates your further distribution of this package by adding +the Classpath Exception to the necessary parts of its GPLv2 code, which +permits you to use that code in combination with other independent +modules not licensed under the GPLv2. However, note that this would +not permit you to commingle code under an incompatible license with +Oracle's GPLv2 licensed code by, for example, cutting and pasting such +code into a file also containing Oracle's GPLv2 licensed code and then +distributing the result. Additionally, if you were to remove the +Classpath Exception from any of the files to which it applies and +distribute the result, you would likely be required to license some or +all of the other code in that distribution under the GPLv2 as well, and +since the GPLv2 is incompatible with the license terms of some items +included in the distribution by Oracle, removing the Classpath +Exception could therefore effectively compromise your ability to +further distribute the package. + +Proceed with caution and we recommend that you obtain the advice of a +lawyer skilled in open source matters before removing the Classpath +Exception or making modifications to this package which may +subsequently be redistributed and/or involve the use of third party +software. + +CLASSPATH EXCEPTION +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License version 2 cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from or +based on this library. If you modify this library, you may extend this +exception to your version of the library, but you are not obligated to +do so. If you do not wish to do so, delete this exception statement +from your version. diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java new file mode 100644 index 00000000000..bd2accc2aa1 --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.mail; + +import java.net.InetAddress; + +/** + * The class Authenticator represents an object that knows how to obtain + * authentication for a network connection. Usually, it will do this by + * prompting the user for information. + *

    + * Applications use this class by creating a subclass, and registering an + * instance of that subclass with the session when it is created. When + * authentication is required, the system will invoke a method on the subclass + * (like getPasswordAuthentication). The subclass's method can query about the + * authentication being requested with a number of inherited methods + * (getRequestingXXX()), and form an appropriate message for the user. + *

    + * All methods that request authentication have a default implementation that + * fails. + * + * @see java.net.Authenticator + * @see javax.mail.Session#getInstance(java.util.Properties, + * javax.mail.Authenticator) + * @see javax.mail.Session#getDefaultInstance(java.util.Properties, + * javax.mail.Authenticator) + * @see javax.mail.Session#requestPasswordAuthentication + * @see javax.mail.PasswordAuthentication + * + * @author Bill Foote + * @author Bill Shannon + */ + +// There are no abstract methods, but to be useful the user must +// subclass. +public abstract class Authenticator { + + /** + * Ask the authenticator for a password. + *

    + * + * @param addr The InetAddress of the site requesting authorization, or null + * if not known. + * @param port the port for the requested connection + * @param protocol The protocol that's requesting the connection (@see + * java.net.Authenticator.getProtocol()) + * @param prompt A prompt string for the user + * + * @return The username/password, or null if one can't be gotten. + */ + final synchronized PasswordAuthentication requestPasswordAuthentication(InetAddress addr, int port, String protocol, + String prompt, String defaultUserName) { + return null; + } + + /** + * @return the InetAddress of the site requesting authorization, or null if it's + * not available. + */ + protected final InetAddress getRequestingSite() { + return null; + } + + /** + * @return the port for the requested connection + */ + protected final int getRequestingPort() { + return -1; + } + + /** + * Give the protocol that's requesting the connection. Often this will be based + * on a URLName. + * + * @return the protcol + * + * @see javax.mail.URLName#getProtocol + */ + protected final String getRequestingProtocol() { + return null; + } + + /** + * @return the prompt string given by the requestor + */ + protected final String getRequestingPrompt() { + return null; + } + + /** + * @return the default user name given by the requestor + */ + protected final String getDefaultUserName() { + return null; + } + + /** + * Called when password authentication is needed. Subclasses should override the + * default implementation, which returns null. + *

    + * + * Note that if this method uses a dialog to prompt the user for this + * information, the dialog needs to block until the user supplies the + * information. This method can not simply return after showing the dialog. + * + * @return The PasswordAuthentication collected from the user, or null if none + * is provided. + */ + protected PasswordAuthentication getPasswordAuthentication() { + return null; + } +} diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java new file mode 100644 index 00000000000..7d95d3b100c --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java @@ -0,0 +1,77 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.mail; + +/** + * The class PasswordAuthentication is a data holder that is used by + * Authenticator. It is simply a repository for a user name and a password. + * + * @see java.net.PasswordAuthentication + * @see javax.mail.Authenticator + * @see javax.mail.Authenticator#getPasswordAuthentication() + * + * @author Bill Foote + */ + +public final class PasswordAuthentication { + /** + * Initialize a new PasswordAuthentication + * + * @param userName the user name + * @param password The user's password + */ + public PasswordAuthentication(String userName, String password) { + } + + /** + * @return the user name + */ + public String getUserName() { + return null; + } + + /** + * @return the password + */ + public String getPassword() { + return null; + } +} diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java new file mode 100644 index 00000000000..d5b2ea79a7b --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java @@ -0,0 +1,325 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.mail; + +import java.lang.reflect.*; +import java.io.*; +import java.net.*; +import java.security.*; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.concurrent.Executor; + +/** + * The Session class represents a mail session and is not subclassed. It + * collects together properties and defaults used by the mail API's. A single + * default session can be shared by multiple applications on the desktop. + * Unshared sessions can also be created. + *

    + * + * The Session class provides access to the protocol providers that implement + * the Store, Transport, and related classes. The + * protocol providers are configured using the following files: + *

      + *
    • javamail.providers and + * javamail.default.providers
    • + *
    • javamail.address.map and + * javamail.default.address.map
    • + *
    + *

    + * Each javamail.X resource file is searched for using three + * methods in the following order: + *

      + *
    1. java.home/conf/javamail.X
    2. + *
    3. META-INF/javamail.X
    4. + *
    5. META-INF/javamail.default.X
    6. + *
    + *

    + * (Where java.home is the value of the "java.home" System property and + * conf is the directory named "conf" if it exists, otherwise the + * directory named "lib"; the "conf" directory was introduced in JDK 1.9.) + *

    + * The first method allows the user to include their own version of the resource + * file by placing it in the conf directory where the + * java.home property points. The second method allows an + * application that uses the JavaMail APIs to include their own resource files + * in their application's or jar file's META-INF directory. The + * javamail.default.X default files are part of the JavaMail + * mail.jar file and should not be supplied by users. + *

    + * + * File location depends upon how the ClassLoader method + * getResource is implemented. Usually, the + * getResource method searches through CLASSPATH until it finds the + * requested file and then stops. + *

    + * + * The ordering of entries in the resource files matters. If multiple entries + * exist, the first entries take precedence over the later entries. For example, + * the first IMAP provider found will be set as the default IMAP implementation + * until explicitly changed by the application. The user- or system-supplied + * resource files augment, they do not override, the default files included with + * the JavaMail APIs. This means that all entries in all files loaded will be + * available. + *

    + * + * javamail.providers and + * javamail.default.providers + *

    + * + * These resource files specify the stores and transports that are available on + * the system, allowing an application to "discover" what store and transport + * implementations are available. The protocol implementations are listed one + * per line. The file format defines four attributes that describe a protocol + * implementation. Each attribute is an "="-separated name-value pair with the + * name in lowercase. Each name-value pair is semi-colon (";") separated. The + * following names are defined. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Attribute Names in Providers Files
    NameDescription
    protocolName assigned to protocol. For example, smtp for + * Transport.
    typeValid entries are store and transport.
    classClass name that implements this protocol.
    vendorOptional string identifying the vendor.
    versionOptional string identifying the version.
    + *

    + * + * Here's an example of META-INF/javamail.default.providers file + * contents: + * + *

    + * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
    + * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
    + * 
    + *

    + * + * The current implementation also supports configuring providers using the Java + * SE {@link java.util.ServiceLoader ServiceLoader} mechanism. When creating + * your own provider, create a {@link Provider} subclass, for example: + * + *

    + * package com.example;
    + *
    + * import javax.mail.Provider;
    + *
    + * public class MyProvider extends Provider {
    + * 	public MyProvider() {
    + * 		super(Provider.Type.STORE, "myprot", MyStore.class.getName(), "Example", null);
    + * 	}
    + * }
    + * 
    + * + * Then include a file named META-INF/services/javax.mail.Provider + * in your jar file that lists the name of your Provider class: + * + *
    + * com.example.MyProvider
    + * 
    + *

    + * + * javamail.address.map and + * javamail.default.address.map + *

    + * + * These resource files map transport address types to the transport protocol. + * The getType method of javax.mail.Address returns + * the address type. The javamail.address.map file maps the + * transport type to the protocol. The file format is a series of name-value + * pairs. Each key name should correspond to an address type that is currently + * installed on the system; there should also be an entry for each + * javax.mail.Address implementation that is present if it is to be + * used. For example, the javax.mail.internet.InternetAddress + * method getType returns "rfc822". Each referenced protocol should + * be installed on the system. For the case of news, below, the + * client should install a Transport provider supporting the nntp protocol. + *

    + * + * Here are the typical contents of a javamail.address.map file: + * + *

    + * rfc822=smtp
    + * news=nntp
    + * 
    + * + * @author John Mani + * @author Bill Shannon + * @author Max Spivak + */ + +public final class Session { + /** + * Get a new Session object. + * + * @param props Properties object that hold relevant properties.
    + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, + * mail.transport.protocol, mail.host, mail.user, and + * mail.from) as the defaults are unlikely to work in all + * cases. + * @param authenticator Authenticator object used to call back to the + * application when a user name and password is needed. + * @return a new Session object + * @see javax.mail.Authenticator + */ + public static Session getInstance(Properties props, Authenticator authenticator) { + return null; + } + + /** + * Get a new Session object. + * + * @param props Properties object that hold relevant properties.
    + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, mail.transport.protocol, + * mail.host, mail.user, and mail.from) as the defaults are + * unlikely to work in all cases. + * @return a new Session object + * @since JavaMail 1.2 + */ + public static Session getInstance(Properties props) { + return null; + } + + /** + * Get the default Session object. If a default has not yet been setup, a new + * Session object is created and installed as the default. + *

    + * + * Since the default session is potentially available to all code executing in + * the same Java virtual machine, and the session can contain security sensitive + * information such as user names and passwords, access to the default session + * is restricted. The Authenticator object, which must be created by the caller, + * is used indirectly to check access permission. The Authenticator object + * passed in when the session is created is compared with the Authenticator + * object passed in to subsequent requests to get the default session. If both + * objects are the same, or are from the same ClassLoader, the request is + * allowed. Otherwise, it is denied. + *

    + * + * Note that if the Authenticator object used to create the session is null, + * anyone can get the default session by passing in null. + *

    + * + * Note also that the Properties object is used only the first time this method + * is called, when a new Session object is created. Subsequent calls return the + * Session object that was created by the first call, and ignore the passed + * Properties object. Use the getInstance method to get a new + * Session object every time the method is called. + *

    + * + * Additional security Permission objects may be used to control access to the + * default session. + *

    + * + * In the current implementation, if a SecurityManager is set, the caller must + * have the RuntimePermission("setFactory") permission. + * + * @param props Properties object. Used only if a new Session object is + * created.
    + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, + * mail.transport.protocol, mail.host, mail.user, and + * mail.from) as the defaults are unlikely to work in all + * cases. + * @param authenticator Authenticator object. Used only if a new Session object + * is created. Otherwise, it must match the Authenticator + * used to create the Session. + * @return the default Session object + */ + public static synchronized Session getDefaultInstance(Properties props, Authenticator authenticator) { + return null; + } + + /** + * Get the default Session object. If a default has not yet been setup, a new + * Session object is created and installed as the default. + *

    + * + * Note that a default session created with no Authenticator is available to all + * code executing in the same Java virtual machine, and the session can contain + * security sensitive information such as user names and passwords. + * + * @param props Properties object. Used only if a new Session object is + * created.
    + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, mail.transport.protocol, + * mail.host, mail.user, and mail.from) as the defaults are + * unlikely to work in all cases. + * @return the default Session object + * @since JavaMail 1.2 + */ + public static Session getDefaultInstance(Properties props) { + return null; + } +} diff --git a/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java new file mode 100644 index 00000000000..dba6c9f88d2 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java @@ -0,0 +1,5 @@ +package javax.script; + +public class CompiledScript { + public Object eval() throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java new file mode 100644 index 00000000000..1e587a0a9bb --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public interface ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java new file mode 100644 index 00000000000..65d124925c9 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java @@ -0,0 +1,3 @@ +package javax.script; + +public class ScriptException extends Exception {} diff --git a/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java new file mode 100644 index 00000000000..b292cb8b9a6 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public class SimpleScriptContext implements ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java new file mode 100644 index 00000000000..3d0c39e724f --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java @@ -0,0 +1,9 @@ +package org.mvel2; + +import java.io.Serializable; + +public class MVEL { + public static Object eval(String expression) { return null; } + public static Serializable compileExpression(String expression) { return null; } + public static Object executeExpression(Object compiledExpression) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java new file mode 100644 index 00000000000..30fef49f0b8 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2; + +import org.mvel2.compiler.CompiledExpression; +import org.mvel2.integration.VariableResolverFactory; + +public class MVELRuntime { + public static Object execute(boolean debugger, CompiledExpression expression, Object ctx, VariableResolverFactory variableFactory) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java new file mode 100644 index 00000000000..ce160eec228 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java @@ -0,0 +1,3 @@ +package org.mvel2; + +public class ParserContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java new file mode 100644 index 00000000000..5c01ab6366d --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java @@ -0,0 +1,7 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public interface Accessor { + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java new file mode 100644 index 00000000000..88630888e67 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java @@ -0,0 +1,10 @@ +package org.mvel2.compiler; + +import org.mvel2.ParserContext; +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledAccExpression implements ExecutableStatement { + public CompiledAccExpression(char[] expression, Class ingressType, ParserContext context) {} + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) { return null; } +} diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java new file mode 100644 index 00000000000..b8a887b4f0d --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java @@ -0,0 +1,9 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledExpression implements ExecutableStatement { + public Object getDirectValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java new file mode 100644 index 00000000000..8aed7035aa6 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -0,0 +1,8 @@ +package org.mvel2.compiler; + +import java.io.Serializable; +import org.mvel2.integration.VariableResolverFactory; + +public interface ExecutableStatement extends Accessor, Serializable { + public Object getValue(Object staticContext, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java new file mode 100644 index 00000000000..3f22268b891 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java @@ -0,0 +1,6 @@ +package org.mvel2.compiler; + +public class ExpressionCompiler { + public ExpressionCompiler(String expression) {} + public CompiledExpression compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java new file mode 100644 index 00000000000..1fb643374b6 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration; + +import java.io.Serializable; + +public interface VariableResolverFactory extends Serializable {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java new file mode 100644 index 00000000000..97463a9e9d3 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration.impl; + +import org.mvel2.integration.VariableResolverFactory; + +public class ImmutableDefaultFactory implements VariableResolverFactory {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java new file mode 100644 index 00000000000..a4be37ada32 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java @@ -0,0 +1,11 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelCompiledScript extends CompiledScript { + public MvelCompiledScript(MvelScriptEngine engine, Serializable compiledScript) {} + public Object eval(ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java new file mode 100644 index 00000000000..6769a6198a4 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java @@ -0,0 +1,12 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelScriptEngine { + public CompiledScript compile(String script) throws ScriptException { return null; } + public Serializable compiledScript(String script) throws ScriptException { return null; } + public Object evaluate(Serializable expression, ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java new file mode 100644 index 00000000000..d0152d28318 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java @@ -0,0 +1,3 @@ +package org.mvel2.templates; + +public class CompiledTemplate {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java new file mode 100644 index 00000000000..333e4164bcd --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java @@ -0,0 +1,7 @@ +package org.mvel2.templates; + +public class TemplateCompiler { + public TemplateCompiler(String template) {} + public static CompiledTemplate compileTemplate(String template) { return null; } + public CompiledTemplate compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java new file mode 100644 index 00000000000..4fec9fa4e30 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2.templates; + +import java.util.Map; + +public class TemplateRuntime { + public static Object eval(String template, Map vars) { return null; } + public static Object execute(CompiledTemplate compiled, Map vars) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java new file mode 100644 index 00000000000..af734cea237 --- /dev/null +++ b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface AttributesMapper {} \ No newline at end of file diff --git a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java new file mode 100644 index 00000000000..06c2b9aa544 --- /dev/null +++ b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface DirContextProcessor {} \ No newline at end of file diff --git a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java new file mode 100644 index 00000000000..0189611802f --- /dev/null +++ b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface LdapOperations {} \ No newline at end of file diff --git a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java index 2c26a3b3b50..fee83cf4ec8 100644 --- a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java +++ b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java @@ -1,5 +1,7 @@ package org.springframework.ldap.core; +import org.springframework.beans.factory.InitializingBean; + import java.util.*; import javax.naming.Name; @@ -9,7 +11,7 @@ import org.springframework.ldap.filter.Filter; import org.springframework.ldap.query.LdapQuery; -public class LdapTemplate { +public class LdapTemplate implements LdapOperations, InitializingBean { public void authenticate(LdapQuery query, String password) { } public boolean authenticate(Name base, String filter, String password) { return true; } @@ -22,7 +24,53 @@ public class LdapTemplate { public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { } + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) {} + + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) {} + + public void search(String base, String filter, NameClassPairCallbackHandler handler) {} + + public List search(String base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, ContextMapper mapper) { return null; } + + public List search(String base, String filter, ContextMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, ContextMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) { return null; } + + public List search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) { return null; } + public DirContextOperations searchForContext(LdapQuery query) { return null; } public T searchForObject(Name base, String filter, ContextMapper mapper) { return null; } + + public T searchForObject(String base, String filter, ContextMapper mapper) { return null; } + + public T searchForObject(String base, String filter, SearchControls searchControls, ContextMapper mapper) { return null; } + + public Object lookup(final String dn) { return new Object(); } + + public DirContextOperations lookupContext(String dn) { return null; } + + public T findByDn(Name dn, final Class clazz) { return null; } + + public void rename(final Name oldDn, final Name newDn) {} + + public List list(final Name base) { return null; } + + public List listBindings(final Name base) { return null; } + + public void unbind(final String dn) {} + + public void unbind(final String dn, boolean recursive) {} } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java new file mode 100644 index 00000000000..40fc853a45b --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java @@ -0,0 +1,3 @@ +package org.springframework.beans.factory; + +public interface InitializingBean {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java similarity index 86% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index 5b94a086e8f..e7dd0fd7673 100644 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -7,6 +7,10 @@ public final class EndpointRequest { public static EndpointRequestMatcher toAnyEndpoint() { return null; } + + public static EndpointRequestMatcher to(String... endpoints) { + return null; + } public static final class EndpointRequestMatcher extends AbstractRequestMatcher {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java new file mode 100644 index 00000000000..fa3ceaaf874 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java @@ -0,0 +1,3 @@ +package org.springframework.expression; + +public interface EvaluationContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java new file mode 100644 index 00000000000..e08ef9cd744 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java @@ -0,0 +1,3 @@ +package org.springframework.expression; + +public class EvaluationException extends RuntimeException {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java new file mode 100644 index 00000000000..2c3fc44075f --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java @@ -0,0 +1,14 @@ +package org.springframework.expression; + +public interface Expression { + + Object getValue() throws EvaluationException; + + Object getValue(EvaluationContext context) throws EvaluationException; + + Class getValueType() throws EvaluationException; + + Class getValueType(EvaluationContext context) throws EvaluationException; + + void setValue(Object rootObject, Object value) throws EvaluationException; +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java new file mode 100644 index 00000000000..4bfbf796c1e --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java @@ -0,0 +1,6 @@ +package org.springframework.expression; + +public interface ExpressionParser { + + Expression parseExpression(String string); +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java new file mode 100644 index 00000000000..4aee45beee9 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -0,0 +1,10 @@ +package org.springframework.expression.spel.standard; + +import org.springframework.expression.*; + +public class SpelExpressionParser implements ExpressionParser { + + public SpelExpressionParser() {} + + public Expression parseExpression(String string) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java new file mode 100644 index 00000000000..67dbc47d6f6 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java @@ -0,0 +1,13 @@ + +package org.springframework.expression.spel.support; + +import org.springframework.expression.*; + +public class SimpleEvaluationContext implements EvaluationContext { + + public static Builder forReadWriteDataBinding() { return null; } + + public static class Builder { + public SimpleEvaluationContext build() { return null; } + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java new file mode 100644 index 00000000000..a3b7cd541f0 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java @@ -0,0 +1,5 @@ +package org.springframework.expression.spel.support; + +import org.springframework.expression.*; + +public class StandardEvaluationContext implements EvaluationContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java new file mode 100644 index 00000000000..800071a30d4 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java @@ -0,0 +1,21 @@ +package org.springframework.jndi; + +import java.util.Properties; +import javax.naming.NamingException; + +public class JndiTemplate { + public JndiTemplate() {} + + public JndiTemplate(Properties environment) {} + + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + @SuppressWarnings("unchecked") + public T lookup(String name, Class requiredType) throws NamingException { + return (T) new Object(); + } + + public void setEnvironment(Properties environment) {} +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java new file mode 100644 index 00000000000..ef4dd7726e0 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java @@ -0,0 +1,9 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +@Indexed +public @interface Component { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java new file mode 100644 index 00000000000..0bfb67d99c1 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java @@ -0,0 +1,9 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface Controller { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java new file mode 100644 index 00000000000..4570cc95b64 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java @@ -0,0 +1,8 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface Indexed { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java new file mode 100644 index 00000000000..2d90f95346a --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value={ElementType.METHOD,ElementType.TYPE}) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestMapping { } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java diff --git a/javascript/config/suites/javascript/frameworks-more b/javascript/config/suites/javascript/frameworks-more index 3445428825f..54ab5115d10 100644 --- a/javascript/config/suites/javascript/frameworks-more +++ b/javascript/config/suites/javascript/frameworks-more @@ -15,7 +15,6 @@ + semmlecode-javascript-queries/NodeJS/DubiousImport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/InvalidExport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/MissingExports.ql: /Frameworks/Node.js -+ semmlecode-javascript-queries/NodeJS/UnusedDependency.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/UnresolvableImport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/React/DirectStateMutation.ql: /Frameworks/React + semmlecode-javascript-queries/React/InconsistentStateUpdate.ql: /Frameworks/React diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 5eb02bc148b..e8575ed8db5 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -13,27 +13,33 @@ + semmlecode-javascript-queries/Security/CWE-078/ShellCommandInjectionFromEnvironment.ql: /Security/CWE/CWE-078 + semmlecode-javascript-queries/Security/CWE-079/ReflectedXss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-079/StoredXss.ql: /Security/CWE/CWE-079 -+ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-079/UnsafeJQueryPlugin.ql: /Security/CWE/CWE-079 ++ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-089/SqlInjection.ql: /Security/CWE/CWE-089 + semmlecode-javascript-queries/Security/CWE-094/CodeInjection.ql: /Security/CWE/CWE-094 ++ semmlecode-javascript-queries/Security/CWE-094/ImproperCodeSanitization.ql: /Security/CWE/CWE-094 + semmlecode-javascript-queries/Security/CWE-094/UnsafeDynamicMethodAccess.ql: /Security/CWE/CWE-094 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-116/DoubleEscaping.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134 ++ semmlecode-javascript-queries/Security/CWE-200/PrivateFileExposure.ql: /Security/CWE/CWE-200 + semmlecode-javascript-queries/Security/CWE-201/PostMessageStar.ql: /Security/CWE/CWE-201 + semmlecode-javascript-queries/Security/CWE-209/StackTraceExposure.ql: /Security/CWE/CWE-209 -+ semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312 ++ semmlecode-javascript-queries/Security/CWE-295/DisablingCertificateValidation.ql: /Security/CWE/CWE-295 ++ semmlecode-javascript-queries/Security/CWE-312/BuildArtifactLeak.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-312/CleartextLogging.ql: /Security/CWE/CWE-312 ++ semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-313/PasswordInConfigurationFile.ql: /Security/CWE/CWE-313 ++ semmlecode-javascript-queries/Security/CWE-327/BadRandomness.ql: /Security/CWE/CWE-327 + semmlecode-javascript-queries/Security/CWE-327/BrokenCryptoAlgorithm.ql: /Security/CWE/CWE-327 + semmlecode-javascript-queries/Security/CWE-338/InsecureRandomness.ql: /Security/CWE/CWE-338 + semmlecode-javascript-queries/Security/CWE-346/CorsMisconfigurationForCredentials.ql: /Security/CWE/CWE-346 + semmlecode-javascript-queries/Security/CWE-352/MissingCsrfMiddleware.ql: /Security/CWE/CWE-352 -+ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-400/PrototypePollution.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-400/PrototypePollutionUtility.ql: /Security/CWE/CWE-400 ++ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-502/UnsafeDeserialization.ql: /Security/CWE/CWE-502 + semmlecode-javascript-queries/Security/CWE-506/HardcodedDataInterpretedAsCode.ql: /Security/CWE/CWE-506 + semmlecode-javascript-queries/Security/CWE-601/ClientSideUrlRedirect.ql: /Security/CWE/CWE-601 @@ -48,6 +54,7 @@ + semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798 + semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807 + semmlecode-javascript-queries/Security/CWE-807/DifferentKindsComparisonBypass.ql: /Security/CWE/CWE-807 ++ semmlecode-javascript-queries/Security/CWE-829/InsecureDownload.ql: /Security/CWE/CWE-829 + semmlecode-javascript-queries/Security/CWE-834/LoopBoundInjection.ql: /Security/CWE/CWE-834 + semmlecode-javascript-queries/Security/CWE-843/TypeConfusionThroughParameterTampering.ql: /Security/CWE/CWE-834 + semmlecode-javascript-queries/Security/CWE-916/InsufficientPasswordHash.ql: /Security/CWE/CWE-916 diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 55994647a94..c8bee62fba8 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "3.8.2" + "typescript": "3.9.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/src/common.ts b/javascript/extractor/lib/typescript/src/common.ts index 1dbe54b4632..c660b7bcb5e 100644 --- a/javascript/extractor/lib/typescript/src/common.ts +++ b/javascript/extractor/lib/typescript/src/common.ts @@ -48,7 +48,7 @@ export class Project { public load(): void { const { config, host } = this; this.program = ts.createProgram(config.fileNames, config.options, host); - this.typeTable.setProgram(this.program); + this.typeTable.setProgram(this.program, this.virtualSourceRoot); } /** @@ -71,10 +71,19 @@ export class Project { redirectedReference: ts.ResolvedProjectReference, options: ts.CompilerOptions) { + let oppositePath = + this.virtualSourceRoot.toVirtualPath(containingFile) || + this.virtualSourceRoot.fromVirtualPath(containingFile); + const { host, resolutionCache } = this; return moduleNames.map((moduleName) => { let redirected = this.redirectModuleName(moduleName, containingFile, options); if (redirected != null) return redirected; + if (oppositePath != null) { + // If the containing file is in the virtual source root, try resolving from the real source root, and vice versa. + redirected = ts.resolveModuleName(moduleName, oppositePath, options, host, resolutionCache).resolvedModule; + if (redirected != null) return redirected; + } return ts.resolveModuleName(moduleName, containingFile, options, host, resolutionCache).resolvedModule; }); } @@ -90,15 +99,7 @@ export class Project { // Get the overridden location of this package, if one exists. let packageEntryPoint = this.packageEntryPoints.get(packageName); - if (packageEntryPoint == null) { - // The package is not overridden, but we have established that it begins with a valid package name. - // Do a lookup in the virtual source root (where dependencies are installed) by changing the 'containing file'. - let virtualContainingFile = this.virtualSourceRoot.toVirtualPath(containingFile); - if (virtualContainingFile != null) { - return ts.resolveModuleName(moduleName, virtualContainingFile, options, this.host, this.resolutionCache).resolvedModule; - } - return null; - } + if (packageEntryPoint == null) return null; // If the requested module name is exactly the overridden package name, // return the entry point file (it is not necessarily called `index.ts`). diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 55d08b5d262..4452ef0e5d6 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -41,17 +41,26 @@ import { Project } from "./common"; import { TypeTable } from "./type_table"; import { VirtualSourceRoot } from "./virtual_source_root"; +// Remove limit on stack trace depth. +Error.stackTraceLimit = Infinity; + interface ParseCommand { command: "parse"; filename: string; } -interface OpenProjectCommand { - command: "open-project"; +interface LoadCommand { tsConfig: string; + sourceRoot: string | null; virtualSourceRoot: string | null; packageEntryPoints: [string, string][]; packageJsonFiles: [string, string][]; } +interface OpenProjectCommand extends LoadCommand { + command: "open-project"; +} +interface GetOwnFilesCommand extends LoadCommand { + command: "get-own-files"; +} interface CloseProjectCommand { command: "close-project"; tsConfig: string; @@ -72,7 +81,7 @@ interface PrepareFilesCommand { interface GetMetadataCommand { command: "get-metadata"; } -type Command = ParseCommand | OpenProjectCommand | CloseProjectCommand +type Command = ParseCommand | OpenProjectCommand | GetOwnFilesCommand | CloseProjectCommand | GetTypeTableCommand | ResetCommand | QuitCommand | PrepareFilesCommand | GetMetadataCommand; /** The state to be shared between commands. */ @@ -362,15 +371,22 @@ function parseSingleFile(filename: string): {ast: ts.SourceFile, code: string} { */ const nodeModulesRex = /[/\\]node_modules[/\\]((?:@[\w.-]+[/\\])?\w[\w.-]*)[/\\](.*)/; -function handleOpenProjectCommand(command: OpenProjectCommand) { - Error.stackTraceLimit = Infinity; - let tsConfigFilename = String(command.tsConfig); - let tsConfig = ts.readConfigFile(tsConfigFilename, ts.sys.readFile); - let basePath = pathlib.dirname(tsConfigFilename); +interface LoadedConfig { + config: ts.ParsedCommandLine; + basePath: string; + packageEntryPoints: Map; + packageJsonFiles: Map; + virtualSourceRoot: VirtualSourceRoot; + ownFiles: string[]; +} + +function loadTsConfig(command: LoadCommand): LoadedConfig { + let tsConfig = ts.readConfigFile(command.tsConfig, ts.sys.readFile); + let basePath = pathlib.dirname(command.tsConfig); let packageEntryPoints = new Map(command.packageEntryPoints); let packageJsonFiles = new Map(command.packageJsonFiles); - let virtualSourceRoot = new VirtualSourceRoot(process.cwd(), command.virtualSourceRoot); + let virtualSourceRoot = new VirtualSourceRoot(command.sourceRoot, command.virtualSourceRoot); /** * Rewrites path segments of form `node_modules/PACK/suffix` to be relative to @@ -398,7 +414,25 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { */ let parseConfigHost: ts.ParseConfigHost = { useCaseSensitiveFileNames: true, - readDirectory: ts.sys.readDirectory, // No need to override traversal/glob matching + readDirectory: (rootDir, extensions, excludes?, includes?, depth?) => { + // Perform the glob matching in both real and virtual source roots. + let exclusions = excludes == null ? [] : [...excludes]; + if (virtualSourceRoot.virtualSourceRoot != null) { + // qltest puts the virtual source root inside the real source root (.testproj). + // Make sure we don't find files inside the virtual source root in this pass. + exclusions.push(virtualSourceRoot.virtualSourceRoot); + } + let originalResults = ts.sys.readDirectory(rootDir, extensions, exclusions, includes, depth) + let virtualDir = virtualSourceRoot.toVirtualPath(rootDir); + if (virtualDir == null) { + return originalResults; + } + // Make sure glob matching does not to discover anything in node_modules. + let virtualExclusions = excludes == null ? [] : [...excludes]; + virtualExclusions.push('**/node_modules/**/*'); + let virtualResults = ts.sys.readDirectory(virtualDir, extensions, virtualExclusions, includes, depth) + return [ ...originalResults, ...virtualResults ]; + }, fileExists: (path: string) => { return ts.sys.fileExists(path) || virtualSourceRoot.toVirtualPathIfFileExists(path) != null @@ -415,7 +449,29 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { } }; let config = ts.parseJsonConfigFileContent(tsConfig.config, parseConfigHost, basePath); - let project = new Project(tsConfigFilename, config, state.typeTable, packageEntryPoints, virtualSourceRoot); + + let ownFiles = config.fileNames.map(file => pathlib.resolve(file)); + + return { config, basePath, packageJsonFiles, packageEntryPoints, virtualSourceRoot, ownFiles }; +} + +/** + * Returns the list of files included in the given tsconfig.json file's include pattern, + * (not including those only references through imports). + */ +function handleGetFileListCommand(command: GetOwnFilesCommand) { + let { config, ownFiles } = loadTsConfig(command); + + console.log(JSON.stringify({ + type: "file-list", + ownFiles, + })); +} + +function handleOpenProjectCommand(command: OpenProjectCommand) { + let { config, packageEntryPoints, virtualSourceRoot, basePath, ownFiles } = loadTsConfig(command); + + let project = new Project(command.tsConfig, config, state.typeTable, packageEntryPoints, virtualSourceRoot); project.load(); state.project = project; @@ -587,9 +643,14 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { return symbol; } + // Unlike in the get-own-files command, this command gets all files we can possibly + // extract type information for, including files referenced outside the tsconfig's inclusion pattern. + let allFiles = program.getSourceFiles().map(sf => pathlib.resolve(sf.fileName)); + console.log(JSON.stringify({ type: "project-opened", - files: program.getSourceFiles().map(sf => pathlib.resolve(sf.fileName)), + ownFiles, + allFiles, })); } @@ -685,6 +746,9 @@ function runReadLineInterface() { case "open-project": handleOpenProjectCommand(req); break; + case "get-own-files": + handleGetFileListCommand(req); + break; case "close-project": handleCloseProjectCommand(req); break; @@ -720,6 +784,7 @@ if (process.argv.length > 2) { tsConfig: argument, packageEntryPoints: [], packageJsonFiles: [], + sourceRoot: null, virtualSourceRoot: null, }); for (let sf of state.project.program.getSourceFiles()) { diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index 287d11c1bd7..b750d5a0d85 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -1,4 +1,5 @@ import * as ts from "./typescript"; +import { VirtualSourceRoot } from "./virtual_source_root"; interface AugmentedSymbol extends ts.Symbol { parent?: AugmentedSymbol; @@ -379,12 +380,15 @@ export class TypeTable { */ public restrictedExpansion = false; + private virtualSourceRoot: VirtualSourceRoot; + /** * Called when a new compiler instance has started. */ - public setProgram(program: ts.Program) { + public setProgram(program: ts.Program, virtualSourceRoot: VirtualSourceRoot) { this.typeChecker = program.getTypeChecker(); this.arbitraryAstNode = program.getSourceFiles()[0]; + this.virtualSourceRoot = virtualSourceRoot; } /** @@ -703,14 +707,21 @@ export class TypeTable { private getSymbolString(symbol: AugmentedSymbol): string { let parent = symbol.parent; if (parent == null || parent.escapedName === ts.InternalSymbolName.Global) { - return "root;" + this.getSymbolDeclarationString(symbol) + ";;" + symbol.name; + return "root;" + this.getSymbolDeclarationString(symbol) + ";;" + this.rewriteSymbolName(symbol); } else if (parent.exports != null && parent.exports.get(symbol.escapedName) === symbol) { - return "member;;" + this.getSymbolId(parent) + ";" + symbol.name; + return "member;;" + this.getSymbolId(parent) + ";" + this.rewriteSymbolName(symbol); } else { - return "other;" + this.getSymbolDeclarationString(symbol) + ";" + this.getSymbolId(parent) + ";" + symbol.name; + return "other;" + this.getSymbolDeclarationString(symbol) + ";" + this.getSymbolId(parent) + ";" + this.rewriteSymbolName(symbol); } } + private rewriteSymbolName(symbol: AugmentedSymbol) { + let { virtualSourceRoot, sourceRoot } = this.virtualSourceRoot; + let { name } = symbol; + if (virtualSourceRoot == null || sourceRoot == null) return name; + return name.replace(virtualSourceRoot, sourceRoot); + } + /** * Gets a string that distinguishes the given symbol from symbols with different * lexical roots, or an empty string if the symbol is not a lexical root. @@ -875,21 +886,23 @@ export class TypeTable { } /** - * Returns the properties of the given type, or `null` if the properties of this - * type could not be computed. + * Returns the properties to extract for the given type or `null` if nothing should be extracted. + * + * For performance reasons we only extract properties needed to recognize promise types at the QL + * level. */ - private tryGetProperties(type: ts.Type) { - // Workaround for https://github.com/Microsoft/TypeScript/issues/30845 - // Should be safe to remove once that has been fixed. - try { - return type.getProperties(); - } catch (e) { - return null; + private getPropertiesToExtract(type: ts.Type) { + if (this.getSelfType(type) === type) { + let thenSymbol = this.typeChecker.getPropertyOfType(type, "then"); + if (thenSymbol != null) { + return [thenSymbol]; + } } + return null; } private extractProperties(type: ts.Type, id: number) { - let props = this.tryGetProperties(type); + let props = this.getPropertiesToExtract(type); if (props == null) return; for (let symbol of props) { let propertyType = this.tryGetTypeOfSymbol(symbol); diff --git a/javascript/extractor/lib/typescript/src/virtual_source_root.ts b/javascript/extractor/lib/typescript/src/virtual_source_root.ts index 5f1bbf2b95e..4753818ef16 100644 --- a/javascript/extractor/lib/typescript/src/virtual_source_root.ts +++ b/javascript/extractor/lib/typescript/src/virtual_source_root.ts @@ -7,23 +7,42 @@ import * as ts from "./typescript"; */ export class VirtualSourceRoot { constructor( - private sourceRoot: string, + public sourceRoot: string | null, /** * Directory whose folder structure mirrors the real source root, but with `node_modules` installed, * or undefined if no virtual source root exists. */ - private virtualSourceRoot: string, + public virtualSourceRoot: string | null, ) {} + private static translate(oldRoot: string, newRoot: string, path: string) { + if (!oldRoot || !newRoot) return null; + let relative = pathlib.relative(oldRoot, path); + if (relative.startsWith('..') || pathlib.isAbsolute(relative)) return null; + return pathlib.join(newRoot, relative); + } + /** * Maps a path under the real source root to the corresponding path in the virtual source root. + * + * Returns `null` for paths already in the virtual source root. */ public toVirtualPath(path: string) { - if (!this.virtualSourceRoot) return null; - let relative = pathlib.relative(this.sourceRoot, path); - if (relative.startsWith('..') || pathlib.isAbsolute(relative)) return null; - return pathlib.join(this.virtualSourceRoot, relative); + let { virtualSourceRoot } = this; + if (path.startsWith(virtualSourceRoot)) { + // 'qltest' creates a virtual source root inside the real source root. + // Make sure such files don't appear to be inside the real source root. + return null; + } + return VirtualSourceRoot.translate(this.sourceRoot, virtualSourceRoot, path); + } + + /** + * Maps a path under the virtual source root to the corresponding path in the real source root. + */ + public fromVirtualPath(path: string) { + return VirtualSourceRoot.translate(this.virtualSourceRoot, this.sourceRoot, path); } /** diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 5afdf469e36..19d96a56650 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -4,31 +4,31 @@ "@types/node@12.7.11": version "12.7.11" - resolved "node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446" + resolved node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446 ansi-regex@^2.0.0: version "2.1.1" - resolved "ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df ansi-styles@^2.2.1: version "2.2.1" - resolved "ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe ansi-styles@^3.1.0: version "3.2.0" - resolved "ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + resolved ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88 dependencies: color-convert "^1.9.0" argparse@^1.0.7: version "1.0.9" - resolved "argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86 dependencies: sprintf-js "~1.0.2" babel-code-frame@^6.22.0: version "6.26.0" - resolved "babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -36,22 +36,22 @@ babel-code-frame@^6.22.0: balanced-match@^1.0.0: version "1.0.0" - resolved "balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767 brace-expansion@^1.1.7: version "1.1.8" - resolved "brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + resolved brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292 dependencies: balanced-match "^1.0.0" concat-map "0.0.1" builtin-modules@^1.1.1: version "1.1.1" - resolved "builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f chalk@^1.1.3: version "1.1.3" - resolved "chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98 dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -61,7 +61,7 @@ chalk@^1.1.3: chalk@^2.3.0: version "2.3.0" - resolved "chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + resolved chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -69,45 +69,45 @@ chalk@^2.3.0: color-convert@^1.9.0: version "1.9.1" - resolved "color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + resolved color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed dependencies: color-name "^1.1.1" color-name@^1.1.1: version "1.1.3" - resolved "color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25 commander@^2.12.1: version "2.13.0" - resolved "commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + resolved commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c concat-map@0.0.1: version "0.0.1" - resolved "concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b diff@^3.2.0: version "3.4.0" - resolved "diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + resolved diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4 esprima@^4.0.0: version "4.0.0" - resolved "esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + resolved esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804 esutils@^2.0.2: version "2.0.2" - resolved "esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b fs.realpath@^1.0.0: version "1.0.0" - resolved "fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f glob@^7.1.1: version "7.1.2" - resolved "glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + resolved glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15 dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -118,93 +118,93 @@ glob@^7.1.1: has-ansi@^2.0.0: version "2.0.0" - resolved "has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91 dependencies: ansi-regex "^2.0.0" has-flag@^2.0.0: version "2.0.0" - resolved "has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + resolved has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51 inflight@^1.0.4: version "1.0.6" - resolved "inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9 dependencies: once "^1.3.0" wrappy "1" inherits@2: version "2.0.3" - resolved "inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de js-tokens@^3.0.2: version "3.0.2" - resolved "js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b js-yaml@^3.7.0: version "3.10.0" - resolved "js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + resolved js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc dependencies: argparse "^1.0.7" esprima "^4.0.0" minimatch@^3.0.4: version "3.0.4" - resolved "minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083 dependencies: brace-expansion "^1.1.7" once@^1.3.0: version "1.4.0" - resolved "once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1 dependencies: wrappy "1" path-is-absolute@^1.0.0: version "1.0.1" - resolved "path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f path-parse@^1.0.5: version "1.0.5" - resolved "path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1 resolve@^1.3.2: version "1.5.0" - resolved "resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + resolved resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36 dependencies: path-parse "^1.0.5" semver@^5.3.0: version "5.5.0" - resolved "semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + resolved semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab sprintf-js@~1.0.2: version "1.0.3" - resolved "sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c strip-ansi@^3.0.0: version "3.0.1" - resolved "strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf dependencies: ansi-regex "^2.0.0" supports-color@^2.0.0: version "2.0.0" - resolved "supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7 supports-color@^4.0.0: version "4.5.0" - resolved "supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + resolved supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b dependencies: has-flag "^2.0.0" tslib@^1.8.0, tslib@^1.8.1: version "1.9.0" - resolved "tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + resolved tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8 tslint@^5.9.1: version "5.9.1" - resolved "tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" + resolved tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" @@ -221,14 +221,14 @@ tslint@^5.9.1: tsutils@^2.12.1: version "2.19.1" - resolved "tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7" + resolved tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7 dependencies: tslib "^1.8.1" -typescript@3.8.2: - version "3.8.2" - resolved typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a +typescript@3.9.2: + version "3.9.2" + resolved typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9 wrappy@1: version "1.0.2" - resolved "wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 36f831720f4..66cb57ba30f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -20,14 +20,18 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.gson.Gson; @@ -77,8 +81,8 @@ import com.semmle.util.trap.TrapWriter; *

  • LGTM_INDEX_EXCLUDE: a newline-separated list of paths to exclude *
  • LGTM_REPOSITORY_FOLDERS_CSV: the path of a CSV file containing file * classifications - *
  • LGTM_INDEX_FILTERS: a newline-separated list of {@link ProjectLayout}-style - * patterns that can be used to refine the list of files to include and exclude + *
  • LGTM_INDEX_FILTERS: a newline-separated list of strings of form "include:PATTERN" + * or "exclude:PATTERN" that can be used to refine the list of files to include and exclude. *
  • LGTM_INDEX_TYPESCRIPT: whether to extract TypeScript *
  • LGTM_INDEX_FILETYPES: a newline-separated list of ".extension:filetype" pairs * specifying which {@link FileType} to use for the given extension; the additional file type @@ -208,6 +212,8 @@ public class AutoBuild { private volatile boolean seenCode = false; private boolean installDependencies = false; private int installDependenciesTimeout; + private final VirtualSourceRoot virtualSourceRoot; + private ExtractorState state; /** The default timeout when running yarn, in milliseconds. */ public static final int INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes @@ -225,9 +231,15 @@ public class AutoBuild { Env.systemEnv() .getInt( "LGTM_INDEX_TYPESCRIPT_INSTALL_DEPS_TIMEOUT", INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT); + this.virtualSourceRoot = makeVirtualSourceRoot(); setupFileTypes(); setupXmlMode(); setupMatchers(); + this.state = new ExtractorState(); + } + + protected VirtualSourceRoot makeVirtualSourceRoot() { + return new VirtualSourceRoot(LGTM_SRC, toRealPath(Paths.get(EnvironmentVariables.getScratchDir()))); } private String getEnvVar(String envVarName) { @@ -528,7 +540,7 @@ public class AutoBuild { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (".js".equals(FileUtil.extension(file.toString()))) extract(extractor, file, null); + if (".js".equals(FileUtil.extension(file.toString()))) extract(extractor, file, true); return super.visitFile(file, attrs); } }; @@ -536,52 +548,123 @@ public class AutoBuild { Files.walkFileTree(externs, visitor); } + /** + * Compares files in the order they should be extracted. + *

    + * The ordering of tsconfig.json files can affect extraction results. Since we + * extract any given source file at most once, and a source file can be included from + * multiple tsconfig.json files, we sometimes have to choose arbitrarily which tsconfig.json + * to use for a given file (which is based on this ordering). + *

    + * We sort them to help ensure reproducible extraction. Additionally, deeply nested files are + * preferred over shallow ones to help ensure files are extracted with the most specific + * tsconfig.json file. + */ + public static final Comparator PATH_ORDERING = new Comparator() { + public int compare(Path f1, Path f2) { + if (f1.getNameCount() != f2.getNameCount()) { + return f2.getNameCount() - f1.getNameCount(); + } + return f1.compareTo(f2); + } + }; + + /** + * Like {@link #PATH_ORDERING} but for {@link File} objects. + */ + public static final Comparator FILE_ORDERING = new Comparator() { + public int compare(File f1, File f2) { + return PATH_ORDERING.compare(f1.toPath(), f2.toPath()); + } + }; + + public class FileExtractors { + FileExtractor defaultExtractor; + Map customExtractors = new LinkedHashMap<>(); + + FileExtractors(FileExtractor defaultExtractor) { + this.defaultExtractor = defaultExtractor; + } + + public FileExtractor forFile(Path f) { + return customExtractors.getOrDefault(FileUtil.extension(f), defaultExtractor); + } + + public FileType fileType(Path f) { + return forFile(f).getFileType(f.toFile()); + } + } + /** Extract all supported candidate files that pass the filters. */ private void extractSource() throws IOException { // default extractor FileExtractor defaultExtractor = new FileExtractor(mkExtractorConfig(), outputConfig, trapCache); + FileExtractors extractors = new FileExtractors(defaultExtractor); + // custom extractor for explicitly specified file types - Map customExtractors = new LinkedHashMap<>(); for (Map.Entry spec : fileTypes.entrySet()) { String extension = spec.getKey(); String fileType = spec.getValue().name(); ExtractorConfig extractorConfig = mkExtractorConfig().withFileType(fileType); - customExtractors.put(extension, new FileExtractor(extractorConfig, outputConfig, trapCache)); + extractors.customExtractors.put(extension, new FileExtractor(extractorConfig, outputConfig, trapCache)); } Set filesToExtract = new LinkedHashSet<>(); List tsconfigFiles = new ArrayList<>(); findFilesToExtract(defaultExtractor, filesToExtract, tsconfigFiles); + tsconfigFiles = tsconfigFiles.stream() + .sorted(PATH_ORDERING) + .collect(Collectors.toList()); + + filesToExtract = filesToExtract.stream() + .sorted(PATH_ORDERING) + .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult.empty; - if (!tsconfigFiles.isEmpty() && this.installDependencies) { - dependencyInstallationResult = this.installDependencies(filesToExtract); + if (!tsconfigFiles.isEmpty()) { + dependencyInstallationResult = this.preparePackagesAndDependencies(filesToExtract); } + Set extractedFiles = new LinkedHashSet<>(); + + // Extract HTML files as they may contain TypeScript + CompletableFuture htmlFuture = extractFiles( + filesToExtract, extractedFiles, extractors, + f -> extractors.fileType(f) == FileType.HTML); + + htmlFuture.join(); // Wait for HTML extraction to be finished. // extract TypeScript projects and files - Set extractedFiles = - extractTypeScript( - defaultExtractor, filesToExtract, tsconfigFiles, dependencyInstallationResult); + extractTypeScript(filesToExtract, extractedFiles, + extractors, tsconfigFiles, dependencyInstallationResult); boolean hasTypeScriptFiles = extractedFiles.size() > 0; // extract remaining files + extractFiles( + filesToExtract, extractedFiles, extractors, + f -> !(hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles))); + } + + private CompletableFuture extractFiles( + Set filesToExtract, + Set extractedFiles, + FileExtractors extractors, + Predicate shouldExtract) { + + List> futures = new ArrayList<>(); for (Path f : filesToExtract) { if (extractedFiles.contains(f)) continue; - if (hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles)) { + if (!shouldExtract.test(f)) { continue; } extractedFiles.add(f); - FileExtractor extractor = defaultExtractor; - if (!fileTypes.isEmpty()) { - String extension = FileUtil.extension(f); - if (customExtractors.containsKey(extension)) extractor = customExtractors.get(extension); - } - extract(extractor, f, null); + futures.add(extract(extractors.forFile(f), f, true)); } + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); } /** @@ -659,7 +742,21 @@ public class AutoBuild { } /** - * Installs dependencies for use by the TypeScript type checker. + * Gets a relative path from from to to provided + * the latter is contained in the former. Otherwise returns null. + * @return a path or null + */ + public static Path tryRelativize(Path from, Path to) { + Path relative = from.relativize(to); + if (relative.startsWith("..") || relative.isAbsolute()) { + return null; + } + return relative; + } + + /** + * Prepares package.json files in a virtual source root, and, if enabled, + * installs dependencies for use by the TypeScript type checker. *

    * Some packages must be downloaded while others exist within the same repo ("monorepos") * but are not in a location where TypeScript would look for it. @@ -677,13 +774,8 @@ public class AutoBuild { * The TypeScript parser wrapper then overrides module resolution so packages can be found * under the virtual source root and via that package location mapping. */ - protected DependencyInstallationResult installDependencies(Set filesToExtract) { - if (!verifyYarnInstallation()) { - return DependencyInstallationResult.empty; - } - - final Path sourceRoot = Paths.get(".").toAbsolutePath(); - final Path virtualSourceRoot = Paths.get(EnvironmentVariables.getScratchDir()).toAbsolutePath(); +protected DependencyInstallationResult preparePackagesAndDependencies(Set filesToExtract) { + final Path sourceRoot = LGTM_SRC; // Read all package.json files and index them by name. Map packageJsonFiles = new LinkedHashMap<>(); @@ -697,6 +789,9 @@ public class AutoBuild { if (!(json instanceof JsonObject)) continue; JsonObject jsonObject = (JsonObject) json; file = file.toAbsolutePath(); + if (tryRelativize(sourceRoot, file) == null) { + continue; // Ignore package.json files outside the source root. + } packageJsonFiles.put(file, jsonObject); String name = getChildAsString(jsonObject, "name"); @@ -767,8 +862,7 @@ public class AutoBuild { // Write the new package.json files to disk for (Path file : packageJsonFiles.keySet()) { - Path relativePath = sourceRoot.relativize(file); - Path virtualFile = virtualSourceRoot.resolve(relativePath); + Path virtualFile = virtualSourceRoot.toVirtualFile(file); try { Files.createDirectories(virtualFile.getParent()); @@ -781,33 +875,35 @@ public class AutoBuild { } // Install dependencies - for (Path file : packageJsonFiles.keySet()) { - Path virtualFile = virtualSourceRoot.resolve(sourceRoot.relativize(file)); - System.out.println("Installing dependencies from " + virtualFile); - ProcessBuilder pb = - new ProcessBuilder( - Arrays.asList( - "yarn", - "install", - "--non-interactive", - "--ignore-scripts", - "--ignore-platform", - "--ignore-engines", - "--ignore-optional", - "--no-default-rc", - "--no-bin-links", - "--pure-lockfile")); - pb.directory(virtualFile.getParent().toFile()); - pb.redirectOutput(Redirect.INHERIT); - pb.redirectError(Redirect.INHERIT); - try { - pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS); - } catch (IOException | InterruptedException ex) { - throw new ResourceError("Could not install dependencies from " + file, ex); + if (this.installDependencies && verifyYarnInstallation()) { + for (Path file : packageJsonFiles.keySet()) { + Path virtualFile = virtualSourceRoot.toVirtualFile(file); + System.out.println("Installing dependencies from " + virtualFile); + ProcessBuilder pb = + new ProcessBuilder( + Arrays.asList( + "yarn", + "install", + "--non-interactive", + "--ignore-scripts", + "--ignore-platform", + "--ignore-engines", + "--ignore-optional", + "--no-default-rc", + "--no-bin-links", + "--pure-lockfile")); + pb.directory(virtualFile.getParent().toFile()); + pb.redirectOutput(Redirect.INHERIT); + pb.redirectError(Redirect.INHERIT); + try { + pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS); + } catch (IOException | InterruptedException ex) { + throw new ResourceError("Could not install dependencies from " + file, ex); + } } } - return new DependencyInstallationResult(virtualSourceRoot, packageMainFile, packagesInRepo); + return new DependencyInstallationResult(packageMainFile, packagesInRepo); } /** @@ -878,44 +974,58 @@ public class AutoBuild { ExtractorConfig config = new ExtractorConfig(true); config = config.withSourceType(getSourceType()); config = config.withTypeScriptMode(typeScriptMode); + config = config.withVirtualSourceRoot(virtualSourceRoot); if (defaultEncoding != null) config = config.withDefaultEncoding(defaultEncoding); return config; } private Set extractTypeScript( - FileExtractor extractor, Set files, + Set extractedFiles, + FileExtractors extractors, List tsconfig, DependencyInstallationResult deps) { - Set extractedFiles = new LinkedHashSet<>(); - if (hasTypeScriptFiles(files) || !tsconfig.isEmpty()) { - ExtractorState extractorState = new ExtractorState(); - TypeScriptParser tsParser = extractorState.getTypeScriptParser(); - verifyTypeScriptInstallation(extractorState); + TypeScriptParser tsParser = state.getTypeScriptParser(); + verifyTypeScriptInstallation(state); + + // Collect all files included in a tsconfig.json inclusion pattern. + // If a given file is referenced by multiple tsconfig files, we prefer to extract it using + // one that includes it rather than just references it. + Set explicitlyIncludedFiles = new LinkedHashSet<>(); + if (tsconfig.size() > 1) { // No prioritization needed if there's only one tsconfig. + for (Path projectPath : tsconfig) { + explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps, virtualSourceRoot)); + } + } // Extract TypeScript projects for (Path projectPath : tsconfig) { File projectFile = projectPath.toFile(); long start = logBeginProcess("Opening project " + projectFile); - ParsedProject project = tsParser.openProject(projectFile, deps); + ParsedProject project = tsParser.openProject(projectFile, deps, virtualSourceRoot); logEndProcess(start, "Done opening project " + projectFile); // Extract all files belonging to this project which are also matched // by our include/exclude filters. - List typeScriptFiles = new ArrayList(); - for (File sourceFile : project.getSourceFiles()) { + List typeScriptFiles = new ArrayList(); + for (File sourceFile : project.getAllFiles()) { Path sourcePath = sourceFile.toPath(); - if (!files.contains(normalizePath(sourcePath))) continue; - if (!FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourcePath))) { + Path normalizedFile = normalizePath(sourcePath); + if (!files.contains(normalizedFile) && !state.getSnippets().containsKey(normalizedFile)) { + continue; + } + if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue; + if (extractors.fileType(sourcePath) != FileType.TYPESCRIPT) { // For the time being, skip non-TypeScript files, even if the TypeScript // compiler can parse them for us. continue; } if (!extractedFiles.contains(sourcePath)) { - typeScriptFiles.add(sourcePath.toFile()); + typeScriptFiles.add(sourcePath); } } - extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractor, extractorState); + typeScriptFiles.sort(PATH_ORDERING); + extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors); tsParser.closeProject(projectFile); } @@ -926,15 +1036,15 @@ public class AutoBuild { } // Extract remaining TypeScript files. - List remainingTypeScriptFiles = new ArrayList(); + List remainingTypeScriptFiles = new ArrayList<>(); for (Path f : files) { if (!extractedFiles.contains(f) - && FileType.forFileExtension(f.toFile()) == FileType.TYPESCRIPT) { - remainingTypeScriptFiles.add(f.toFile()); + && extractors.fileType(f) == FileType.TYPESCRIPT) { + remainingTypeScriptFiles.add(f); } } if (!remainingTypeScriptFiles.isEmpty()) { - extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractor, extractorState); + extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors); } // The TypeScript compiler instance is no longer needed. @@ -1018,15 +1128,17 @@ public class AutoBuild { } public void extractTypeScriptFiles( - List files, + List files, Set extractedFiles, - FileExtractor extractor, - ExtractorState extractorState) { - extractorState.getTypeScriptParser().prepareFiles(files); - for (File f : files) { - Path path = f.toPath(); + FileExtractors extractors) { + List list = files + .stream() + .sorted(PATH_ORDERING) + .map(p -> p.toFile()).collect(Collectors.toList()); + state.getTypeScriptParser().prepareFiles(list); + for (Path path : files) { extractedFiles.add(path); - extract(extractor, f.toPath(), extractorState); + extract(extractors.forFile(path), path, false); } } @@ -1069,10 +1181,13 @@ public class AutoBuild { *

    If the state is {@code null}, the extraction job will be submitted to the {@link * #threadPool}, otherwise extraction will happen on the main thread. */ - protected void extract(FileExtractor extractor, Path file, ExtractorState state) { - if (state == null && threadPool != null) - threadPool.submit(() -> doExtract(extractor, file, state)); - else doExtract(extractor, file, state); + protected CompletableFuture extract(FileExtractor extractor, Path file, boolean concurrent) { + if (concurrent && threadPool != null) { + return CompletableFuture.runAsync(() -> doExtract(extractor, file, state), threadPool); + } else { + doExtract(extractor, file, state); + return CompletableFuture.completedFuture(null); + } } private void doExtract(FileExtractor extractor, Path file, ExtractorState state) { diff --git a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java index 460a6573f6b..5dd6bd60b6a 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java +++ b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java @@ -6,31 +6,19 @@ import java.util.Map; /** Contains the results of installing dependencies. */ public class DependencyInstallationResult { - private Path virtualSourceRoot; private Map packageEntryPoints; private Map packageJsonFiles; public static final DependencyInstallationResult empty = - new DependencyInstallationResult(null, Collections.emptyMap(), Collections.emptyMap()); + new DependencyInstallationResult(Collections.emptyMap(), Collections.emptyMap()); public DependencyInstallationResult( - Path virtualSourceRoot, Map packageEntryPoints, Map packageJsonFiles) { this.packageEntryPoints = packageEntryPoints; this.packageJsonFiles = packageJsonFiles; } - /** - * Returns the virtual source root or null if no virtual source root exists. - * - * The virtual source root is a directory hierarchy that mirrors the real source - * root, where dependencies are installed. - */ - public Path getVirtualSourceRoot() { - return virtualSourceRoot; - } - /** * Returns the mapping from package names to the TypeScript file that should * act as its main entry point. diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java index d77f71f04ce..2593a3a1e59 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java @@ -146,7 +146,7 @@ public class ExtractionMetrics { public void stopPhase( ExtractionPhase - event /* technically not needed, but useful for documentation and sanity checking */) { + event /* technically not needed, but useful for documentation and consistency checking */) { if (stack.isEmpty()) { failTimings( String.format( diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java index dd3976eec78..5cd5d5ec4b1 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java @@ -1,8 +1,5 @@ package com.semmle.js.extractor; -import com.semmle.js.parser.JcornWrapper; -import com.semmle.util.data.StringUtil; -import com.semmle.util.exception.UserError; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.StandardCharsets; @@ -12,6 +9,10 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import com.semmle.js.parser.JcornWrapper; +import com.semmle.util.data.StringUtil; +import com.semmle.util.exception.UserError; + /** * Configuration options that affect the behaviour of the extractor. * @@ -236,6 +237,8 @@ public class ExtractorConfig { /** The default character encoding to use for parsing source files. */ private String defaultEncoding; + private VirtualSourceRoot virtualSourceRoot; + public ExtractorConfig(boolean experimental) { this.ecmaVersion = experimental ? ECMAVersion.ECMA2020 : ECMAVersion.ECMA2019; this.platform = Platform.AUTO; @@ -252,6 +255,7 @@ public class ExtractorConfig { this.typescriptMode = TypeScriptMode.NONE; this.e4x = experimental; this.defaultEncoding = StandardCharsets.UTF_8.name(); + this.virtualSourceRoot = VirtualSourceRoot.none; } public ExtractorConfig(ExtractorConfig that) { @@ -272,6 +276,7 @@ public class ExtractorConfig { this.typescriptMode = that.typescriptMode; this.typescriptRam = that.typescriptRam; this.defaultEncoding = that.defaultEncoding; + this.virtualSourceRoot = that.virtualSourceRoot; } public ECMAVersion getEcmaVersion() { @@ -452,6 +457,16 @@ public class ExtractorConfig { return res; } + public VirtualSourceRoot getVirtualSourceRoot() { + return virtualSourceRoot; + } + + public ExtractorConfig withVirtualSourceRoot(VirtualSourceRoot virtualSourceRoot) { + ExtractorConfig res = new ExtractorConfig(this); + res.virtualSourceRoot = virtualSourceRoot; + return res; + } + @Override public String toString() { return "ExtractorConfig [ecmaVersion=" @@ -486,6 +501,8 @@ public class ExtractorConfig { + typescriptMode + ", defaultEncoding=" + defaultEncoding + + ", virtualSourceRoot=" + + virtualSourceRoot + "]"; } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java index f347efdf86e..33505e8bb37 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java @@ -1,5 +1,8 @@ package com.semmle.js.extractor; +import java.nio.file.Path; +import java.util.concurrent.ConcurrentHashMap; + import com.semmle.js.parser.TypeScriptParser; /** @@ -17,16 +20,28 @@ import com.semmle.js.parser.TypeScriptParser; */ public class ExtractorState { private TypeScriptParser typeScriptParser = new TypeScriptParser(); + + private final ConcurrentHashMap snippets = new ConcurrentHashMap<>(); public TypeScriptParser getTypeScriptParser() { return typeScriptParser; } + /** + * Returns the mapping that denotes where a snippet file originated from. + * + *

    The map is thread-safe and may be mutated by the caller. + */ + public ConcurrentHashMap getSnippets() { + return snippets; + } + /** * Makes this semantically equivalent to a fresh state, but may internally retain shared resources * that are expensive to reacquire. */ public void reset() { typeScriptParser.reset(); + snippets.clear(); } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index cacc6b6cc9c..861f7630995 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -1,5 +1,17 @@ package com.semmle.js.extractor; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase; import com.semmle.js.extractor.trapcache.CachingTrapWriter; import com.semmle.js.extractor.trapcache.ITrapCache; @@ -10,16 +22,6 @@ import com.semmle.util.files.FileUtil; import com.semmle.util.io.WholeIO; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.regex.Pattern; /** * The file extractor extracts a single file and handles source archive population and TRAP caching; @@ -47,7 +49,7 @@ public class FileExtractor { HTML(".htm", ".html", ".xhtm", ".xhtml", ".vue") { @Override public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) { - return new HTMLExtractor(config); + return new HTMLExtractor(config, state); } @Override @@ -293,7 +295,7 @@ public class FileExtractor { @Override public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) { - return new TypeScriptExtractor(config, state.getTypeScriptParser()); + return new TypeScriptExtractor(config, state); } @Override @@ -398,6 +400,10 @@ public class FileExtractor { /** @return the number of lines of code extracted, or {@code null} if the file was cached */ public Integer extract(File f, ExtractorState state) throws IOException { + FileSnippet snippet = state.getSnippets().get(f.toPath()); + if (snippet != null) { + return this.extractSnippet(f.toPath(), snippet, state); + } // populate source archive String source = new WholeIO(config.getDefaultEncoding()).strictread(f); @@ -414,6 +420,25 @@ public class FileExtractor { return extractContents(f, fileLabel, source, locationManager, state); } + /** + * Extract the contents of a file that is a snippet from another file. + * + *

    A trap file will be derived from the snippet file, but its file label, source locations, and + * source archive entry are based on the original file. + */ + private Integer extractSnippet(Path file, FileSnippet origin, ExtractorState state) throws IOException { + TrapWriter trapwriter = outputConfig.getTrapWriterFactory().mkTrapWriter(file.toFile()); + + File originalFile = origin.getOriginalFile().toFile(); + Label fileLabel = trapwriter.populateFile(originalFile); + LocationManager locationManager = new LocationManager(originalFile, trapwriter, fileLabel); + locationManager.setStart(origin.getLine(), origin.getColumn()); + + String source = new WholeIO(config.getDefaultEncoding()).strictread(file); + + return extractContents(file.toFile(), fileLabel, source, locationManager, state); + } + /** * Extract the contents of a file, potentially making use of cached information. * @@ -436,20 +461,20 @@ public class FileExtractor { * obviously, no caching is done in that scenario. */ private Integer extractContents( - File f, Label fileLabel, String source, LocationManager locationManager, ExtractorState state) + File extractedFile, Label fileLabel, String source, LocationManager locationManager, ExtractorState state) throws IOException { ExtractionMetrics metrics = new ExtractionMetrics(); metrics.startPhase(ExtractionPhase.FileExtractor_extractContents); metrics.setLength(source.length()); metrics.setFileLabel(fileLabel); TrapWriter trapwriter = locationManager.getTrapWriter(); - FileType fileType = getFileType(f); + FileType fileType = getFileType(extractedFile); File cacheFile = null, // the cache file for this extraction resultFile = null; // the final result TRAP file for this extraction if (bumpIdCounter(trapwriter)) { - resultFile = outputConfig.getTrapWriterFactory().getTrapFileFor(f); + resultFile = outputConfig.getTrapWriterFactory().getTrapFileFor(extractedFile); } // check whether we can perform caching if (resultFile != null && fileType.isTrapCachingAllowed()) { @@ -475,7 +500,7 @@ public class FileExtractor { trapwriter = new CachingTrapWriter(cacheFile, resultFile); bumpIdCounter(trapwriter); // re-initialise the location manager, since it keeps a reference to the TRAP writer - locationManager = new LocationManager(f, trapwriter, locationManager.getFileLabel()); + locationManager = new LocationManager(extractedFile, trapwriter, locationManager.getFileLabel()); } // now do the extraction itself @@ -484,9 +509,9 @@ public class FileExtractor { IExtractor extractor = fileType.mkExtractor(config, state); TextualExtractor textualExtractor = new TextualExtractor( - trapwriter, locationManager, source, config.getExtractLines(), metrics); + trapwriter, locationManager, source, config.getExtractLines(), metrics, extractedFile); LoCInfo loc = extractor.extract(textualExtractor); - int numLines = textualExtractor.getNumLines(); + int numLines = textualExtractor.isSnippet() ? 0 : textualExtractor.getNumLines(); int linesOfCode = loc.getLinesOfCode(), linesOfComments = loc.getLinesOfComments(); trapwriter.addTuple("numlines", fileLabel, numLines, linesOfCode, linesOfComments); trapwriter.addTuple("filetype", fileLabel, fileType.toString()); diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java new file mode 100644 index 00000000000..12d74fcef3f --- /dev/null +++ b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java @@ -0,0 +1,44 @@ +package com.semmle.js.extractor; + +import java.nio.file.Path; + +import com.semmle.js.extractor.ExtractorConfig.SourceType; + +/** + * Denotes where a code snippet originated from within a file. + */ +public class FileSnippet { + private Path originalFile; + private int line; + private int column; + private int topLevelKind; + private SourceType sourceType; + + public FileSnippet(Path originalFile, int line, int column, int topLevelKind, SourceType sourceType) { + this.originalFile = originalFile; + this.line = line; + this.column = column; + this.topLevelKind = topLevelKind; + this.sourceType = sourceType; + } + + public Path getOriginalFile() { + return originalFile; + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + public int getTopLevelKind() { + return topLevelKind; + } + + public SourceType getSourceType() { + return sourceType; + } +} diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index 3274741a970..7a1f1222884 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -1,12 +1,17 @@ package com.semmle.js.extractor; +import java.io.File; +import java.nio.file.Path; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractorConfig.Platform; import com.semmle.js.extractor.ExtractorConfig.SourceType; import com.semmle.js.parser.ParseError; import com.semmle.util.data.StringUtil; +import com.semmle.util.io.WholeIO; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.util.regex.Pattern; + import net.htmlparser.jericho.Attribute; import net.htmlparser.jericho.Attributes; import net.htmlparser.jericho.CharacterReference; @@ -26,9 +31,11 @@ public class HTMLExtractor implements IExtractor { Pattern.CASE_INSENSITIVE); private final ExtractorConfig config; + private final ExtractorState state; - public HTMLExtractor(ExtractorConfig config) { + public HTMLExtractor(ExtractorConfig config, ExtractorState state) { this.config = config.withPlatform(Platform.WEB); + this.state = state; } @Override @@ -49,7 +56,7 @@ public class HTMLExtractor implements IExtractor { for (Element elt : src.getAllElements()) { LoCInfo snippetLoC = null; if (elt.getName().equals(HTMLElementName.SCRIPT)) { - SourceType sourceType = getScriptSourceType(elt); + SourceType sourceType = getScriptSourceType(elt, textualExtractor.getExtractedFile()); if (sourceType != null) { // Jericho sometimes misparses empty elements, which will show up as start tags // ending in "/"; we manually exclude these cases to avoid spurious syntax errors @@ -57,6 +64,7 @@ public class HTMLExtractor implements IExtractor { Segment content = elt.getContent(); String source = content.toString(); + boolean isTypeScript = isTypeScriptTag(elt); /* * Script blocks in XHTML files may wrap (parts of) their code inside CDATA sections. @@ -79,7 +87,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, contentStart.getRow(), - contentStart.getColumn()); + contentStart.getColumn(), + isTypeScript); } } } else { @@ -101,7 +110,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, valueStart.getRow(), - valueStart.getColumn()); + valueStart.getColumn(), + false /* isTypeScript */); } else if (source.startsWith("javascript:")) { source = source.substring(11); snippetLoC = @@ -112,7 +122,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, valueStart.getRow(), - valueStart.getColumn() + 11); + valueStart.getColumn() + 11, + false /* isTypeScript */); } } } @@ -139,16 +150,23 @@ public class HTMLExtractor implements IExtractor { * Deduce the {@link SourceType} with which the given script element should be * extracted, returning null if it cannot be determined. */ - private SourceType getScriptSourceType(Element script) { + private SourceType getScriptSourceType(Element script, File file) { String scriptType = getAttributeValueLC(script, "type"); - String scriptLanguage = getAttributeValueLC(script, "language"); + String scriptLanguage = getScriptLanguage(script); + + SourceType fallbackSourceType = config.getSourceType(); + if (file.getName().endsWith(".vue")) { + fallbackSourceType = SourceType.MODULE; + } + + if (isTypeScriptTag(script)) return fallbackSourceType; // if `type` and `language` are both either missing, contain the // string "javascript", or if `type` is the string "text/jsx", this is a plain script if ((scriptType == null || scriptType.contains("javascript") || "text/jsx".equals(scriptType)) && (scriptLanguage == null || scriptLanguage.contains("javascript"))) // use default source type - return config.getSourceType(); + return fallbackSourceType; // if `type` is "text/babel", the source type depends on the `data-plugins` attribute if ("text/babel".equals(scriptType)) { @@ -156,7 +174,7 @@ public class HTMLExtractor implements IExtractor { if (plugins != null && plugins.contains("transform-es2015-modules-umd")) { return SourceType.MODULE; } - return config.getSourceType(); + return fallbackSourceType; } // if `type` is "module", extract as module @@ -165,6 +183,23 @@ public class HTMLExtractor implements IExtractor { return null; } + private String getScriptLanguage(Element script) { + String scriptLanguage = getAttributeValueLC(script, "language"); + + if (scriptLanguage == null) { // Vue templates use 'lang' instead of 'language'. + scriptLanguage = getAttributeValueLC(script, "lang"); + } + return scriptLanguage; + } + + private boolean isTypeScriptTag(Element script) { + String language = getScriptLanguage(script); + if ("ts".equals(language) || "typescript".equals(language)) return true; + String type = getAttributeValueLC(script, "type"); + if (type != null && type.contains("typescript")) return true; + return false; + } + /** * Get the value of attribute attr of element elt in lower case; if the * attribute has no value, null is returned. @@ -181,7 +216,27 @@ public class HTMLExtractor implements IExtractor { TextualExtractor textualExtractor, String source, int line, - int column) { + int column, + boolean isTypeScript) { + if (isTypeScript) { + Path file = textualExtractor.getExtractedFile().toPath(); + FileSnippet snippet = new FileSnippet(file, line, column, toplevelKind, config.getSourceType()); + VirtualSourceRoot vroot = config.getVirtualSourceRoot(); + // Vue files are special in that they can be imported as modules, and may only contain one + + + \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected new file mode 100644 index 00000000000..34e9a5ea94c --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected @@ -0,0 +1,33 @@ +| tst-multi-character-sanitization.js:3:13:3:57 | content ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:3:30:3:49 | <.*cript.*\\/scrip.*> | <.*cript.*\\/scrip.*> | +| tst-multi-character-sanitization.js:4:13:4:47 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:4:30:4:40 | on\\w+=".*" | on\\w+=".*" | +| tst-multi-character-sanitization.js:5:13:5:49 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:5:30:5:42 | on\\w+=\\'.*\\' | on\\w+=\\'.*\\' | +| tst-multi-character-sanitization.js:9:13:9:47 | content ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:9:30:9:39 | <.*cript.* | <.*cript.* | +| tst-multi-character-sanitization.js:10:13:10:49 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:10:30:10:42 | .on\\w+=.*".*" | .on\\w+=.*".*" | +| tst-multi-character-sanitization.js:11:13:11:51 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:11:30:11:44 | .on\\w+=.*\\'.*\\' | .on\\w+=.*\\'.*\\' | +| tst-multi-character-sanitization.js:19:3:19:35 | respons ... pt, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:18:18:18:24 |